gallium: Simplify winsys buffer interface.
The properties of a buffer represented by struct pipe_buffer_handle are now basically constant over its lifetime. The state tracker gets to deal with any more complex buffer semantics it may need to provide.
This commit is contained in:
@@ -70,10 +70,10 @@ static void *intel_buffer_map(struct pipe_winsys *winsys,
|
|||||||
{
|
{
|
||||||
unsigned drm_flags = 0;
|
unsigned drm_flags = 0;
|
||||||
|
|
||||||
if (flags & PIPE_BUFFER_FLAG_WRITE)
|
if (flags & PIPE_BUFFER_USAGE_CPU_WRITE)
|
||||||
drm_flags |= DRM_BO_FLAG_WRITE;
|
drm_flags |= DRM_BO_FLAG_WRITE;
|
||||||
|
|
||||||
if (flags & PIPE_BUFFER_FLAG_READ)
|
if (flags & PIPE_BUFFER_USAGE_CPU_READ)
|
||||||
drm_flags |= DRM_BO_FLAG_READ;
|
drm_flags |= DRM_BO_FLAG_READ;
|
||||||
|
|
||||||
return driBOMap( dri_bo(buf), drm_flags, 0 );
|
return driBOMap( dri_bo(buf), drm_flags, 0 );
|
||||||
@@ -103,50 +103,48 @@ intel_buffer_reference(struct pipe_winsys *winsys,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Grabs the hardware lock!
|
|
||||||
*/
|
|
||||||
static int intel_buffer_data(struct pipe_winsys *winsys,
|
|
||||||
struct pipe_buffer_handle *buf,
|
|
||||||
unsigned size, const void *data,
|
|
||||||
unsigned usage )
|
|
||||||
{
|
|
||||||
driBOData( dri_bo(buf), size, data, 0 );
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int intel_buffer_subdata(struct pipe_winsys *winsys,
|
|
||||||
struct pipe_buffer_handle *buf,
|
|
||||||
unsigned long offset,
|
|
||||||
unsigned long size,
|
|
||||||
const void *data)
|
|
||||||
{
|
|
||||||
driBOSubData( dri_bo(buf), offset, size, data );
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int intel_buffer_get_subdata(struct pipe_winsys *winsys,
|
|
||||||
struct pipe_buffer_handle *buf,
|
|
||||||
unsigned long offset,
|
|
||||||
unsigned long size,
|
|
||||||
void *data)
|
|
||||||
{
|
|
||||||
driBOGetSubData( dri_bo(buf), offset, size, data );
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Pipe has no concept of pools. We choose the tex/region pool
|
/* Pipe has no concept of pools. We choose the tex/region pool
|
||||||
* for all buffers.
|
* for all buffers.
|
||||||
|
* Grabs the hardware lock!
|
||||||
*/
|
*/
|
||||||
static struct pipe_buffer_handle *
|
static struct pipe_buffer_handle *
|
||||||
intel_buffer_create(struct pipe_winsys *winsys,
|
intel_buffer_create(struct pipe_winsys *winsys,
|
||||||
unsigned alignment,
|
unsigned alignment,
|
||||||
unsigned flags,
|
unsigned usage,
|
||||||
unsigned hint )
|
unsigned size )
|
||||||
{
|
{
|
||||||
struct _DriBufferObject *buffer;
|
struct _DriBufferObject *buffer;
|
||||||
struct intel_pipe_winsys *iws = intel_pipe_winsys(winsys);
|
struct intel_pipe_winsys *iws = intel_pipe_winsys(winsys);
|
||||||
|
unsigned flags = 0;
|
||||||
|
|
||||||
|
if (usage & (PIPE_BUFFER_USAGE_VERTEX /*| IWS_BUFFER_USAGE_LOCAL*/)) {
|
||||||
|
flags |= DRM_BO_FLAG_MEM_LOCAL | DRM_BO_FLAG_CACHED;
|
||||||
|
} else {
|
||||||
|
flags |= DRM_BO_FLAG_MEM_VRAM | DRM_BO_FLAG_MEM_TT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (usage & PIPE_BUFFER_USAGE_GPU_READ)
|
||||||
|
flags |= DRM_BO_FLAG_READ;
|
||||||
|
|
||||||
|
if (usage & PIPE_BUFFER_USAGE_GPU_WRITE)
|
||||||
|
flags |= DRM_BO_FLAG_WRITE;
|
||||||
|
|
||||||
|
/* drm complains if we don't set any read/write flags.
|
||||||
|
*/
|
||||||
|
if ((flags & (DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE)) == 0)
|
||||||
|
flags |= DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
if (flags & IWS_BUFFER_USAGE_EXE)
|
||||||
|
flags |= DRM_BO_FLAG_EXE;
|
||||||
|
|
||||||
|
if (usage & IWS_BUFFER_USAGE_CACHED)
|
||||||
|
flags |= DRM_BO_FLAG_CACHED;
|
||||||
|
#endif
|
||||||
|
|
||||||
driGenBuffers( iws->regionPool,
|
driGenBuffers( iws->regionPool,
|
||||||
"pipe buffer", 1, &buffer, alignment, flags, hint );
|
"pipe buffer", 1, &buffer, alignment, flags, 0 );
|
||||||
|
driBOData( buffer, size, NULL, 0 );
|
||||||
return pipe_bo(buffer);
|
return pipe_bo(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -219,15 +217,12 @@ intel_i915_surface_alloc_storage(struct pipe_winsys *winsys,
|
|||||||
surf->pitch = round_up(width, alignment / surf->cpp);
|
surf->pitch = round_up(width, alignment / surf->cpp);
|
||||||
|
|
||||||
assert(!surf->buffer);
|
assert(!surf->buffer);
|
||||||
surf->buffer = winsys->buffer_create(winsys, alignment, 0, 0);
|
surf->buffer = winsys->buffer_create(winsys, alignment,
|
||||||
|
PIPE_BUFFER_USAGE_PIXEL,
|
||||||
|
surf->pitch * surf->cpp * height);
|
||||||
if(!surf->buffer)
|
if(!surf->buffer)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
ret = winsys->buffer_data(winsys,
|
|
||||||
surf->buffer,
|
|
||||||
surf->pitch * surf->cpp * height,
|
|
||||||
NULL,
|
|
||||||
PIPE_BUFFER_USAGE_PIXEL);
|
|
||||||
if(ret) {
|
if(ret) {
|
||||||
winsys->buffer_reference(winsys, &surf->buffer, NULL);
|
winsys->buffer_reference(winsys, &surf->buffer, NULL);
|
||||||
return ret;
|
return ret;
|
||||||
@@ -285,9 +280,6 @@ intel_create_pipe_winsys( int fd )
|
|||||||
iws->winsys.buffer_map = intel_buffer_map;
|
iws->winsys.buffer_map = intel_buffer_map;
|
||||||
iws->winsys.buffer_unmap = intel_buffer_unmap;
|
iws->winsys.buffer_unmap = intel_buffer_unmap;
|
||||||
iws->winsys.buffer_reference = intel_buffer_reference;
|
iws->winsys.buffer_reference = intel_buffer_reference;
|
||||||
iws->winsys.buffer_data = intel_buffer_data;
|
|
||||||
iws->winsys.buffer_subdata = intel_buffer_subdata;
|
|
||||||
iws->winsys.buffer_get_subdata = intel_buffer_get_subdata;
|
|
||||||
iws->winsys.flush_frontbuffer = intel_flush_frontbuffer;
|
iws->winsys.flush_frontbuffer = intel_flush_frontbuffer;
|
||||||
iws->winsys.printf = intel_printf;
|
iws->winsys.printf = intel_printf;
|
||||||
iws->winsys.get_name = intel_get_name;
|
iws->winsys.get_name = intel_get_name;
|
||||||
|
@@ -185,7 +185,7 @@ i915_draw_elements( struct pipe_context *pipe,
|
|||||||
void *buf
|
void *buf
|
||||||
= pipe->winsys->buffer_map(pipe->winsys,
|
= pipe->winsys->buffer_map(pipe->winsys,
|
||||||
i915->vertex_buffer[i].buffer,
|
i915->vertex_buffer[i].buffer,
|
||||||
PIPE_BUFFER_FLAG_READ);
|
PIPE_BUFFER_USAGE_CPU_READ);
|
||||||
draw_set_mapped_vertex_buffer(draw, i, buf);
|
draw_set_mapped_vertex_buffer(draw, i, buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -193,7 +193,7 @@ i915_draw_elements( struct pipe_context *pipe,
|
|||||||
if (indexBuffer) {
|
if (indexBuffer) {
|
||||||
void *mapped_indexes
|
void *mapped_indexes
|
||||||
= pipe->winsys->buffer_map(pipe->winsys, indexBuffer,
|
= pipe->winsys->buffer_map(pipe->winsys, indexBuffer,
|
||||||
PIPE_BUFFER_FLAG_READ);
|
PIPE_BUFFER_USAGE_CPU_READ);
|
||||||
draw_set_mapped_element_buffer(draw, indexSize, mapped_indexes);
|
draw_set_mapped_element_buffer(draw, indexSize, mapped_indexes);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@@ -99,16 +99,14 @@ i915_vbuf_render_allocate_vertices( struct vbuf_render *render,
|
|||||||
|
|
||||||
/* FIXME: handle failure */
|
/* FIXME: handle failure */
|
||||||
assert(!i915->vbo);
|
assert(!i915->vbo);
|
||||||
i915->vbo = winsys->buffer_create(winsys, 64, 0, 0);
|
i915->vbo = winsys->buffer_create(winsys, 64, I915_BUFFER_USAGE_LIT_VERTEX,
|
||||||
winsys->buffer_data( winsys, i915->vbo,
|
size);
|
||||||
size, NULL,
|
|
||||||
I915_BUFFER_USAGE_LIT_VERTEX );
|
|
||||||
|
|
||||||
i915->dirty |= I915_NEW_VBO;
|
i915->dirty |= I915_NEW_VBO;
|
||||||
|
|
||||||
return winsys->buffer_map(winsys,
|
return winsys->buffer_map(winsys,
|
||||||
i915->vbo,
|
i915->vbo,
|
||||||
PIPE_BUFFER_FLAG_WRITE );
|
PIPE_BUFFER_USAGE_CPU_WRITE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -476,7 +476,8 @@ static void i915_set_constant_buffer(struct pipe_context *pipe,
|
|||||||
{
|
{
|
||||||
void *mapped;
|
void *mapped;
|
||||||
if (buf->size &&
|
if (buf->size &&
|
||||||
(mapped = ws->buffer_map(ws, buf->buffer, PIPE_BUFFER_FLAG_READ))) {
|
(mapped = ws->buffer_map(ws, buf->buffer,
|
||||||
|
PIPE_BUFFER_USAGE_CPU_READ))) {
|
||||||
memcpy(i915->current.constants[shader], mapped, buf->size);
|
memcpy(i915->current.constants[shader], mapped, buf->size);
|
||||||
ws->buffer_unmap(ws, buf->buffer);
|
ws->buffer_unmap(ws, buf->buffer);
|
||||||
i915->current.num_user_constants[shader]
|
i915->current.num_user_constants[shader]
|
||||||
|
@@ -490,15 +490,11 @@ i915_texture_create(struct pipe_context *pipe, struct pipe_texture **pt)
|
|||||||
sizeof(struct i915_texture) - sizeof(struct pipe_texture));
|
sizeof(struct i915_texture) - sizeof(struct pipe_texture));
|
||||||
|
|
||||||
if (i915->flags.is_i945 ? i945_miptree_layout(pipe, tex) :
|
if (i915->flags.is_i945 ? i945_miptree_layout(pipe, tex) :
|
||||||
i915_miptree_layout(pipe, tex)) {
|
i915_miptree_layout(pipe, tex))
|
||||||
tex->buffer = pipe->winsys->buffer_create(pipe->winsys, 64, 0, 0);
|
tex->buffer = pipe->winsys->buffer_create(pipe->winsys, 64,
|
||||||
|
PIPE_BUFFER_USAGE_PIXEL,
|
||||||
if (tex->buffer)
|
|
||||||
pipe->winsys->buffer_data(pipe->winsys, tex->buffer,
|
|
||||||
tex->pitch * tex->base.cpp *
|
tex->pitch * tex->base.cpp *
|
||||||
tex->total_height, NULL,
|
tex->total_height);
|
||||||
PIPE_BUFFER_USAGE_PIXEL);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!tex->buffer) {
|
if (!tex->buffer) {
|
||||||
FREE(tex);
|
FREE(tex);
|
||||||
|
@@ -255,15 +255,12 @@ static void upload_constant_buffer(struct brw_context *brw)
|
|||||||
/* FIXME: buffer size is num_consts + num_immediates */
|
/* FIXME: buffer size is num_consts + num_immediates */
|
||||||
if (brw->vs.prog_data->num_consts) {
|
if (brw->vs.prog_data->num_consts) {
|
||||||
/* map the vertex constant buffer and copy to curbe: */
|
/* map the vertex constant buffer and copy to curbe: */
|
||||||
ws->buffer_map(ws, cbuffer->buffer, 0);
|
void *data = ws->buffer_map(ws, cbuffer->buffer, 0);
|
||||||
/* FIXME: this is wrong. the cbuffer->size currently
|
/* FIXME: this is wrong. the cbuffer->size currently
|
||||||
* represents size of consts + immediates. so if we'll
|
* represents size of consts + immediates. so if we'll
|
||||||
* have both we'll copy over the end of the buffer
|
* have both we'll copy over the end of the buffer
|
||||||
* with the subsequent memcpy */
|
* with the subsequent memcpy */
|
||||||
ws->buffer_get_subdata(ws, cbuffer->buffer,
|
memcpy(&buf[offset], data, cbuffer->size);
|
||||||
0,
|
|
||||||
cbuffer->size,
|
|
||||||
&buf[offset]);
|
|
||||||
ws->buffer_unmap(ws, cbuffer->buffer);
|
ws->buffer_unmap(ws, cbuffer->buffer);
|
||||||
offset += cbuffer->size;
|
offset += cbuffer->size;
|
||||||
}
|
}
|
||||||
|
@@ -240,7 +240,7 @@ boolean brw_upload_vertex_buffers( struct brw_context *brw )
|
|||||||
|
|
||||||
for (i = 0; i < nr_enabled; i++) {
|
for (i = 0; i < nr_enabled; i++) {
|
||||||
OUT_BATCH( vbp.vb[i].vb0.dword );
|
OUT_BATCH( vbp.vb[i].vb0.dword );
|
||||||
OUT_RELOC( vbp.vb[i].buffer, PIPE_BUFFER_FLAG_READ,
|
OUT_RELOC( vbp.vb[i].buffer, PIPE_BUFFER_USAGE_GPU_READ,
|
||||||
vbp.vb[i].offset);
|
vbp.vb[i].offset);
|
||||||
OUT_BATCH( vbp.vb[i].max_index );
|
OUT_BATCH( vbp.vb[i].max_index );
|
||||||
OUT_BATCH( vbp.vb[i].instance_data_step_rate );
|
OUT_BATCH( vbp.vb[i].instance_data_step_rate );
|
||||||
@@ -290,8 +290,8 @@ boolean brw_upload_indices( struct brw_context *brw,
|
|||||||
|
|
||||||
BEGIN_BATCH(4, 0);
|
BEGIN_BATCH(4, 0);
|
||||||
OUT_BATCH( ib.header.dword );
|
OUT_BATCH( ib.header.dword );
|
||||||
OUT_RELOC( index_buffer, PIPE_BUFFER_FLAG_READ, start);
|
OUT_RELOC( index_buffer, PIPE_BUFFER_USAGE_GPU_READ, start);
|
||||||
OUT_RELOC( index_buffer, PIPE_BUFFER_FLAG_READ, start + count);
|
OUT_RELOC( index_buffer, PIPE_BUFFER_USAGE_GPU_READ, start + count);
|
||||||
OUT_BATCH( 0 );
|
OUT_BATCH( 0 );
|
||||||
ADVANCE_BATCH();
|
ADVANCE_BATCH();
|
||||||
}
|
}
|
||||||
|
@@ -245,7 +245,7 @@ static void upload_depthbuffer(struct brw_context *brw)
|
|||||||
// (depth_surface->region->tiled << 27) |
|
// (depth_surface->region->tiled << 27) |
|
||||||
(BRW_SURFACE_2D << 29));
|
(BRW_SURFACE_2D << 29));
|
||||||
OUT_RELOC(depth_surface->buffer,
|
OUT_RELOC(depth_surface->buffer,
|
||||||
PIPE_BUFFER_FLAG_READ | PIPE_BUFFER_FLAG_WRITE, 0);
|
PIPE_BUFFER_USAGE_GPU_READ | PIPE_BUFFER_USAGE_GPU_WRITE, 0);
|
||||||
OUT_BATCH((BRW_SURFACE_MIPMAPLAYOUT_BELOW << 1) |
|
OUT_BATCH((BRW_SURFACE_MIPMAPLAYOUT_BELOW << 1) |
|
||||||
((depth_surface->pitch - 1) << 6) |
|
((depth_surface->pitch - 1) << 6) |
|
||||||
((depth_surface->height - 1) << 19));
|
((depth_surface->height - 1) << 19));
|
||||||
@@ -465,10 +465,10 @@ static void upload_state_base_address( struct brw_context *brw )
|
|||||||
BEGIN_BATCH(6, INTEL_BATCH_NO_CLIPRECTS);
|
BEGIN_BATCH(6, INTEL_BATCH_NO_CLIPRECTS);
|
||||||
OUT_BATCH(CMD_STATE_BASE_ADDRESS << 16 | (6 - 2));
|
OUT_BATCH(CMD_STATE_BASE_ADDRESS << 16 | (6 - 2));
|
||||||
OUT_RELOC(brw->pool[BRW_GS_POOL].buffer,
|
OUT_RELOC(brw->pool[BRW_GS_POOL].buffer,
|
||||||
PIPE_BUFFER_FLAG_READ,
|
PIPE_BUFFER_USAGE_GPU_READ,
|
||||||
1); /* General state base address */
|
1); /* General state base address */
|
||||||
OUT_RELOC(brw->pool[BRW_SS_POOL].buffer,
|
OUT_RELOC(brw->pool[BRW_SS_POOL].buffer,
|
||||||
PIPE_BUFFER_FLAG_READ,
|
PIPE_BUFFER_USAGE_GPU_READ,
|
||||||
1); /* Surface state base address */
|
1); /* Surface state base address */
|
||||||
OUT_BATCH(1); /* Indirect object base address */
|
OUT_BATCH(1); /* Indirect object base address */
|
||||||
OUT_BATCH(1); /* General state upper bound */
|
OUT_BATCH(1); /* General state upper bound */
|
||||||
|
@@ -91,13 +91,9 @@ static void brw_init_pool( struct brw_context *brw,
|
|||||||
pool->brw = brw;
|
pool->brw = brw;
|
||||||
|
|
||||||
pool->buffer = brw->pipe.winsys->buffer_create(brw->pipe.winsys,
|
pool->buffer = brw->pipe.winsys->buffer_create(brw->pipe.winsys,
|
||||||
4096, 0, 0);
|
4096,
|
||||||
|
0 /* DRM_BO_FLAG_MEM_TT */,
|
||||||
brw->pipe.winsys->buffer_data(brw->pipe.winsys,
|
size);
|
||||||
pool->buffer,
|
|
||||||
size,
|
|
||||||
NULL,
|
|
||||||
0 /* DRM_BO_FLAG_MEM_TT */);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void brw_destroy_pool( struct brw_context *brw,
|
static void brw_destroy_pool( struct brw_context *brw,
|
||||||
|
@@ -308,15 +308,11 @@ brw_texture_create(struct pipe_context *pipe, struct pipe_texture **pt)
|
|||||||
memset(&tex->base + 1, 0,
|
memset(&tex->base + 1, 0,
|
||||||
sizeof(struct brw_texture) - sizeof(struct pipe_texture));
|
sizeof(struct brw_texture) - sizeof(struct pipe_texture));
|
||||||
|
|
||||||
if (brw_miptree_layout(pipe, tex)) {
|
if (brw_miptree_layout(pipe, tex))
|
||||||
tex->buffer = pipe->winsys->buffer_create(pipe->winsys, 64, 0, 0);
|
tex->buffer = pipe->winsys->buffer_create(pipe->winsys, 64,
|
||||||
|
PIPE_BUFFER_USAGE_PIXEL,
|
||||||
if (tex->buffer)
|
|
||||||
pipe->winsys->buffer_data(pipe->winsys, tex->buffer,
|
|
||||||
tex->pitch * tex->base.cpp *
|
tex->pitch * tex->base.cpp *
|
||||||
tex->total_height, NULL,
|
tex->total_height);
|
||||||
PIPE_BUFFER_USAGE_PIXEL);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!tex->buffer) {
|
if (!tex->buffer) {
|
||||||
FREE(tex);
|
FREE(tex);
|
||||||
|
@@ -177,27 +177,21 @@ enum pipe_texture_target {
|
|||||||
#define PIPE_SURFACE_STATUS_CLEAR 2
|
#define PIPE_SURFACE_STATUS_CLEAR 2
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Buffer access flags
|
|
||||||
*/
|
|
||||||
#define PIPE_BUFFER_FLAG_READ 0x1
|
|
||||||
#define PIPE_BUFFER_FLAG_WRITE 0x2
|
|
||||||
#define PIPE_BUFFER_FLAG_MEM_LOCAL 0x4
|
|
||||||
#define PIPE_BUFFER_FLAG_CACHED 0x8
|
|
||||||
#define PIPE_BUFFER_FLAG_CUSTOM (1<<16)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Buffer usage flags
|
* Buffer usage flags
|
||||||
*/
|
*/
|
||||||
#define PIPE_BUFFER_USAGE_PIXEL (1 << 0)
|
#define PIPE_BUFFER_USAGE_CPU_READ (1 << 0)
|
||||||
#define PIPE_BUFFER_USAGE_VERTEX (1 << 1)
|
#define PIPE_BUFFER_USAGE_CPU_WRITE (1 << 1)
|
||||||
#define PIPE_BUFFER_USAGE_INDEX (1 << 2)
|
#define PIPE_BUFFER_USAGE_GPU_READ (1 << 2)
|
||||||
#define PIPE_BUFFER_USAGE_CONSTANT (1 << 3)
|
#define PIPE_BUFFER_USAGE_GPU_WRITE (1 << 3)
|
||||||
|
#define PIPE_BUFFER_USAGE_PIXEL (1 << 4)
|
||||||
|
#define PIPE_BUFFER_USAGE_VERTEX (1 << 5)
|
||||||
|
#define PIPE_BUFFER_USAGE_INDEX (1 << 6)
|
||||||
|
#define PIPE_BUFFER_USAGE_CONSTANT (1 << 7)
|
||||||
/** Pipe driver custam usage flags should be greater or equal to this value */
|
/** Pipe driver custam usage flags should be greater or equal to this value */
|
||||||
#define PIPE_BUFFER_USAGE_CUSTOM (1 << 16)
|
#define PIPE_BUFFER_USAGE_CUSTOM (1 << 16)
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Flush types:
|
* Flush types:
|
||||||
*/
|
*/
|
||||||
|
@@ -37,8 +37,8 @@ static INLINE void *
|
|||||||
pipe_surface_map(struct pipe_surface *surface)
|
pipe_surface_map(struct pipe_surface *surface)
|
||||||
{
|
{
|
||||||
return (char *)surface->winsys->buffer_map( surface->winsys, surface->buffer,
|
return (char *)surface->winsys->buffer_map( surface->winsys, surface->buffer,
|
||||||
PIPE_BUFFER_FLAG_WRITE |
|
PIPE_BUFFER_USAGE_CPU_WRITE |
|
||||||
PIPE_BUFFER_FLAG_READ )
|
PIPE_BUFFER_USAGE_CPU_READ )
|
||||||
+ surface->offset;
|
+ surface->offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -93,17 +93,20 @@ struct pipe_winsys
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The buffer manager is modeled after the dri_bufmgr interface, which
|
* Buffer management. Buffer attributes are mostly fixed over its lifetime.
|
||||||
* in turn is modeled after the ARB_vertex_buffer_object extension,
|
*
|
||||||
* but this is the subset that gallium cares about. Remember that
|
* Remember that gallium gets to choose the interface it needs, and the
|
||||||
* gallium gets to choose the interface it needs, and the window
|
* window systems must then implement that interface (rather than the
|
||||||
* systems must then implement that interface (rather than the
|
|
||||||
* other way around...).
|
* other way around...).
|
||||||
|
*
|
||||||
|
* usage is a bitmask of PIPE_BUFFER_USAGE_PIXEL/VERTEX/INDEX/CONSTANT. This
|
||||||
|
* usage argument is only an optimization hint, not a guarantee, therefore
|
||||||
|
* proper behavior must be observed in all circumstances.
|
||||||
*/
|
*/
|
||||||
struct pipe_buffer_handle *(*buffer_create)( struct pipe_winsys *sws,
|
struct pipe_buffer_handle *(*buffer_create)( struct pipe_winsys *sws,
|
||||||
unsigned alignment,
|
unsigned alignment,
|
||||||
unsigned flags,
|
unsigned usage,
|
||||||
unsigned hint );
|
unsigned size );
|
||||||
|
|
||||||
/** Create a buffer that wraps user-space data */
|
/** Create a buffer that wraps user-space data */
|
||||||
struct pipe_buffer_handle *(*user_buffer_create)(struct pipe_winsys *sws,
|
struct pipe_buffer_handle *(*user_buffer_create)(struct pipe_winsys *sws,
|
||||||
@@ -116,7 +119,7 @@ struct pipe_winsys
|
|||||||
*/
|
*/
|
||||||
void *(*buffer_map)( struct pipe_winsys *sws,
|
void *(*buffer_map)( struct pipe_winsys *sws,
|
||||||
struct pipe_buffer_handle *buf,
|
struct pipe_buffer_handle *buf,
|
||||||
unsigned flags );
|
unsigned usage );
|
||||||
|
|
||||||
void (*buffer_unmap)( struct pipe_winsys *sws,
|
void (*buffer_unmap)( struct pipe_winsys *sws,
|
||||||
struct pipe_buffer_handle *buf );
|
struct pipe_buffer_handle *buf );
|
||||||
@@ -126,44 +129,8 @@ struct pipe_winsys
|
|||||||
struct pipe_buffer_handle **ptr,
|
struct pipe_buffer_handle **ptr,
|
||||||
struct pipe_buffer_handle *buf );
|
struct pipe_buffer_handle *buf );
|
||||||
|
|
||||||
/**
|
|
||||||
* Create the data store of a buffer and optionally initialize it.
|
|
||||||
*
|
|
||||||
* usage is a bitmask of PIPE_BUFFER_USAGE_PIXEL/VERTEX/INDEX/CONSTANT. This
|
|
||||||
* usage argument is only an optimization hint, not a guarantee, therefore
|
|
||||||
* proper behavior must be observed in all circumstances.
|
|
||||||
*
|
|
||||||
* Returns zero on success.
|
|
||||||
*/
|
|
||||||
int (*buffer_data)(struct pipe_winsys *sws,
|
|
||||||
struct pipe_buffer_handle *buf,
|
|
||||||
unsigned size, const void *data,
|
|
||||||
unsigned usage);
|
|
||||||
|
|
||||||
/**
|
/** Set ptr = fence, with reference counting */
|
||||||
* Modify some or all of the data contained in a buffer's data store.
|
|
||||||
*
|
|
||||||
* Returns zero on success.
|
|
||||||
*/
|
|
||||||
int (*buffer_subdata)(struct pipe_winsys *sws,
|
|
||||||
struct pipe_buffer_handle *buf,
|
|
||||||
unsigned long offset,
|
|
||||||
unsigned long size,
|
|
||||||
const void *data);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Query some or all of the data contained in a buffer's data store.
|
|
||||||
*
|
|
||||||
* Returns zero on success.
|
|
||||||
*/
|
|
||||||
int (*buffer_get_subdata)(struct pipe_winsys *sws,
|
|
||||||
struct pipe_buffer_handle *buf,
|
|
||||||
unsigned long offset,
|
|
||||||
unsigned long size,
|
|
||||||
void *data);
|
|
||||||
|
|
||||||
|
|
||||||
/** Set ptr = buf, with reference counting */
|
|
||||||
void (*fence_reference)( struct pipe_winsys *sws,
|
void (*fence_reference)( struct pipe_winsys *sws,
|
||||||
struct pipe_fence_handle **ptr,
|
struct pipe_fence_handle **ptr,
|
||||||
struct pipe_fence_handle *fence );
|
struct pipe_fence_handle *fence );
|
||||||
|
@@ -46,8 +46,8 @@
|
|||||||
static struct pipe_buffer_handle *
|
static struct pipe_buffer_handle *
|
||||||
buffer_handle_create(struct pipe_winsys *winsys,
|
buffer_handle_create(struct pipe_winsys *winsys,
|
||||||
unsigned alignment,
|
unsigned alignment,
|
||||||
unsigned flags,
|
unsigned usage,
|
||||||
unsigned hint)
|
unsigned size)
|
||||||
{
|
{
|
||||||
struct pipe_buffer_handle *handle;
|
struct pipe_buffer_handle *handle;
|
||||||
|
|
||||||
@@ -57,8 +57,8 @@ buffer_handle_create(struct pipe_winsys *winsys,
|
|||||||
|
|
||||||
handle->refcount = 1;
|
handle->refcount = 1;
|
||||||
handle->alignment = alignment;
|
handle->alignment = alignment;
|
||||||
handle->flags = flags;
|
handle->usage = usage;
|
||||||
handle->hint = hint;
|
handle->size = size;
|
||||||
|
|
||||||
handle->buf = &null_buffer;
|
handle->buf = &null_buffer;
|
||||||
|
|
||||||
@@ -73,7 +73,7 @@ buffer_handle_create_user(struct pipe_winsys *winsys,
|
|||||||
struct pipe_buffer_handle *handle;
|
struct pipe_buffer_handle *handle;
|
||||||
struct pipe_buffer *buf;
|
struct pipe_buffer *buf;
|
||||||
|
|
||||||
handle = buffer_handle_create(winsys, 1, 0, 0);
|
handle = buffer_handle_create(winsys, 1, 0, size);
|
||||||
if(!handle)
|
if(!handle)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
@@ -129,46 +129,6 @@ buffer_handle_reference(struct pipe_winsys *winsys,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int
|
|
||||||
buffer_handle_subdata(struct pipe_winsys *winsys,
|
|
||||||
struct pipe_buffer_handle *handle,
|
|
||||||
unsigned long offset,
|
|
||||||
unsigned long size,
|
|
||||||
const void *data)
|
|
||||||
{
|
|
||||||
void *map;
|
|
||||||
assert(handle);
|
|
||||||
assert(data);
|
|
||||||
map = buffer_handle_map(winsys, handle, PIPE_BUFFER_FLAG_WRITE);
|
|
||||||
if(map) {
|
|
||||||
memcpy((char *)map + offset, data, size);
|
|
||||||
buffer_handle_unmap(winsys, handle);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
|
||||||
buffer_handle_get_subdata(struct pipe_winsys *winsys,
|
|
||||||
struct pipe_buffer_handle *handle,
|
|
||||||
unsigned long offset,
|
|
||||||
unsigned long size,
|
|
||||||
void *data)
|
|
||||||
{
|
|
||||||
void *map;
|
|
||||||
assert(handle);
|
|
||||||
assert(data);
|
|
||||||
map = buffer_handle_map(winsys, handle, PIPE_BUFFER_FLAG_READ);
|
|
||||||
if(map) {
|
|
||||||
memcpy(data, (char *)map + offset, size);
|
|
||||||
buffer_handle_unmap(winsys, handle);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
buffer_handle_init_winsys(struct pipe_winsys *winsys)
|
buffer_handle_init_winsys(struct pipe_winsys *winsys)
|
||||||
{
|
{
|
||||||
@@ -177,6 +137,4 @@ buffer_handle_init_winsys(struct pipe_winsys *winsys)
|
|||||||
winsys->buffer_map = buffer_handle_map;
|
winsys->buffer_map = buffer_handle_map;
|
||||||
winsys->buffer_unmap = buffer_handle_unmap;
|
winsys->buffer_unmap = buffer_handle_unmap;
|
||||||
winsys->buffer_reference = buffer_handle_reference;
|
winsys->buffer_reference = buffer_handle_reference;
|
||||||
winsys->buffer_subdata = buffer_handle_subdata;
|
|
||||||
winsys->buffer_get_subdata = buffer_handle_get_subdata;
|
|
||||||
}
|
}
|
||||||
|
@@ -55,8 +55,8 @@ struct pipe_buffer_handle
|
|||||||
|
|
||||||
/** Allocation characteristics */
|
/** Allocation characteristics */
|
||||||
unsigned alignment;
|
unsigned alignment;
|
||||||
unsigned flags;
|
unsigned usage;
|
||||||
unsigned hint;
|
unsigned size;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The actual buffer.
|
* The actual buffer.
|
||||||
|
@@ -241,7 +241,8 @@ mm_bufmgr_create_from_buffer(struct pipe_buffer *buffer,
|
|||||||
mm->buffer = buffer;
|
mm->buffer = buffer;
|
||||||
|
|
||||||
mm->map = buffer_map(mm->buffer,
|
mm->map = buffer_map(mm->buffer,
|
||||||
PIPE_BUFFER_FLAG_READ | PIPE_BUFFER_FLAG_WRITE );
|
PIPE_BUFFER_USAGE_CPU_READ |
|
||||||
|
PIPE_BUFFER_USAGE_CPU_WRITE);
|
||||||
if(!mm->map)
|
if(!mm->map)
|
||||||
goto failure;
|
goto failure;
|
||||||
|
|
||||||
|
@@ -246,8 +246,8 @@ pool_bufmgr_create(struct buffer_manager *provider,
|
|||||||
goto failure;
|
goto failure;
|
||||||
|
|
||||||
pool->map = buffer_map(pool->buffer,
|
pool->map = buffer_map(pool->buffer,
|
||||||
PIPE_BUFFER_FLAG_READ |
|
PIPE_BUFFER_USAGE_CPU_READ |
|
||||||
PIPE_BUFFER_FLAG_WRITE );
|
PIPE_BUFFER_USAGE_CPU_WRITE);
|
||||||
if(!pool->map)
|
if(!pool->map)
|
||||||
goto failure;
|
goto failure;
|
||||||
|
|
||||||
|
@@ -50,7 +50,7 @@ softpipe_map_constant_buffers(struct softpipe_context *sp)
|
|||||||
for (i = 0; i < 2; i++) {
|
for (i = 0; i < 2; i++) {
|
||||||
if (sp->constants[i].size)
|
if (sp->constants[i].size)
|
||||||
sp->mapped_constants[i] = ws->buffer_map(ws, sp->constants[i].buffer,
|
sp->mapped_constants[i] = ws->buffer_map(ws, sp->constants[i].buffer,
|
||||||
PIPE_BUFFER_FLAG_READ);
|
PIPE_BUFFER_USAGE_CPU_READ);
|
||||||
}
|
}
|
||||||
|
|
||||||
draw_set_mapped_constant_buffer(sp->draw,
|
draw_set_mapped_constant_buffer(sp->draw,
|
||||||
@@ -122,7 +122,7 @@ softpipe_draw_elements(struct pipe_context *pipe,
|
|||||||
void *buf
|
void *buf
|
||||||
= pipe->winsys->buffer_map(pipe->winsys,
|
= pipe->winsys->buffer_map(pipe->winsys,
|
||||||
sp->vertex_buffer[i].buffer,
|
sp->vertex_buffer[i].buffer,
|
||||||
PIPE_BUFFER_FLAG_READ);
|
PIPE_BUFFER_USAGE_CPU_READ);
|
||||||
draw_set_mapped_vertex_buffer(draw, i, buf);
|
draw_set_mapped_vertex_buffer(draw, i, buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -130,7 +130,7 @@ softpipe_draw_elements(struct pipe_context *pipe,
|
|||||||
if (indexBuffer) {
|
if (indexBuffer) {
|
||||||
void *mapped_indexes
|
void *mapped_indexes
|
||||||
= pipe->winsys->buffer_map(pipe->winsys, indexBuffer,
|
= pipe->winsys->buffer_map(pipe->winsys, indexBuffer,
|
||||||
PIPE_BUFFER_FLAG_READ);
|
PIPE_BUFFER_USAGE_CPU_READ);
|
||||||
draw_set_mapped_element_buffer(draw, indexSize, mapped_indexes);
|
draw_set_mapped_element_buffer(draw, indexSize, mapped_indexes);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@@ -91,12 +91,9 @@ softpipe_texture_create(struct pipe_context *pipe, struct pipe_texture **pt)
|
|||||||
|
|
||||||
softpipe_texture_layout(spt);
|
softpipe_texture_layout(spt);
|
||||||
|
|
||||||
spt->buffer = pipe->winsys->buffer_create(pipe->winsys, 32, 0, 0);
|
spt->buffer = pipe->winsys->buffer_create(pipe->winsys, 32,
|
||||||
|
PIPE_BUFFER_USAGE_PIXEL,
|
||||||
if (spt->buffer) {
|
spt->buffer_size);
|
||||||
pipe->winsys->buffer_data(pipe->winsys, spt->buffer, spt->buffer_size,
|
|
||||||
NULL, PIPE_BUFFER_USAGE_PIXEL);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!spt->buffer) {
|
if (!spt->buffer) {
|
||||||
FREE(spt);
|
FREE(spt);
|
||||||
|
@@ -165,48 +165,6 @@ xm_buffer_reference(struct pipe_winsys *pws,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
|
||||||
xm_buffer_data(struct pipe_winsys *pws, struct pipe_buffer_handle *buf,
|
|
||||||
unsigned size, const void *data, unsigned usage )
|
|
||||||
{
|
|
||||||
struct xm_buffer *xm_buf = xm_bo(buf);
|
|
||||||
assert(!xm_buf->userBuffer);
|
|
||||||
if (xm_buf->size != size) {
|
|
||||||
if (xm_buf->data)
|
|
||||||
align_free(xm_buf->data);
|
|
||||||
/* align to 16-byte multiple for Cell */
|
|
||||||
xm_buf->data = align_malloc(size, 16);
|
|
||||||
xm_buf->size = size;
|
|
||||||
}
|
|
||||||
if (data)
|
|
||||||
memcpy(xm_buf->data, data, size);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
xm_buffer_subdata(struct pipe_winsys *pws, struct pipe_buffer_handle *buf,
|
|
||||||
unsigned long offset, unsigned long size, const void *data)
|
|
||||||
{
|
|
||||||
struct xm_buffer *xm_buf = xm_bo(buf);
|
|
||||||
GLubyte *b = (GLubyte *) xm_buf->data;
|
|
||||||
assert(!xm_buf->userBuffer);
|
|
||||||
assert(b);
|
|
||||||
memcpy(b + offset, data, size);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
xm_buffer_get_subdata(struct pipe_winsys *pws, struct pipe_buffer_handle *buf,
|
|
||||||
unsigned long offset, unsigned long size, void *data)
|
|
||||||
{
|
|
||||||
const struct xm_buffer *xm_buf = xm_bo(buf);
|
|
||||||
const GLubyte *b = (GLubyte *) xm_buf->data;
|
|
||||||
assert(!xm_buf->userBuffer);
|
|
||||||
assert(b);
|
|
||||||
memcpy(data, b + offset, size);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Display a surface that's in a tiled configuration. That is, all the
|
* Display a surface that's in a tiled configuration. That is, all the
|
||||||
@@ -317,11 +275,16 @@ xm_get_name(struct pipe_winsys *pws)
|
|||||||
static struct pipe_buffer_handle *
|
static struct pipe_buffer_handle *
|
||||||
xm_buffer_create(struct pipe_winsys *pws,
|
xm_buffer_create(struct pipe_winsys *pws,
|
||||||
unsigned alignment,
|
unsigned alignment,
|
||||||
unsigned flags,
|
unsigned usage,
|
||||||
unsigned hints)
|
unsigned size)
|
||||||
{
|
{
|
||||||
struct xm_buffer *buffer = CALLOC_STRUCT(xm_buffer);
|
struct xm_buffer *buffer = CALLOC_STRUCT(xm_buffer);
|
||||||
buffer->refcount = 1;
|
buffer->refcount = 1;
|
||||||
|
|
||||||
|
/* align to 16-byte multiple for Cell */
|
||||||
|
buffer->data = align_malloc(size, max(alignment, 16));
|
||||||
|
buffer->size = size;
|
||||||
|
|
||||||
return pipe_bo(buffer);
|
return pipe_bo(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -359,7 +322,6 @@ xm_surface_alloc_storage(struct pipe_winsys *winsys,
|
|||||||
unsigned flags)
|
unsigned flags)
|
||||||
{
|
{
|
||||||
const unsigned alignment = 64;
|
const unsigned alignment = 64;
|
||||||
int ret;
|
|
||||||
|
|
||||||
surf->width = width;
|
surf->width = width;
|
||||||
surf->height = height;
|
surf->height = height;
|
||||||
@@ -372,20 +334,12 @@ xm_surface_alloc_storage(struct pipe_winsys *winsys,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
assert(!surf->buffer);
|
assert(!surf->buffer);
|
||||||
surf->buffer = winsys->buffer_create(winsys, alignment, 0, 0);
|
surf->buffer = winsys->buffer_create(winsys, alignment,
|
||||||
|
PIPE_BUFFER_USAGE_PIXEL,
|
||||||
|
surf->pitch * surf->cpp * height);
|
||||||
if(!surf->buffer)
|
if(!surf->buffer)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
ret = winsys->buffer_data(winsys,
|
|
||||||
surf->buffer,
|
|
||||||
surf->pitch * surf->cpp * height,
|
|
||||||
NULL,
|
|
||||||
0);
|
|
||||||
if(ret) {
|
|
||||||
winsys->buffer_reference(winsys, &surf->buffer, NULL);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -454,9 +408,6 @@ xmesa_get_pipe_winsys_aub(void)
|
|||||||
ws->buffer_map = xm_buffer_map;
|
ws->buffer_map = xm_buffer_map;
|
||||||
ws->buffer_unmap = xm_buffer_unmap;
|
ws->buffer_unmap = xm_buffer_unmap;
|
||||||
ws->buffer_reference = xm_buffer_reference;
|
ws->buffer_reference = xm_buffer_reference;
|
||||||
ws->buffer_data = xm_buffer_data;
|
|
||||||
ws->buffer_subdata = xm_buffer_subdata;
|
|
||||||
ws->buffer_get_subdata = xm_buffer_get_subdata;
|
|
||||||
|
|
||||||
ws->surface_alloc = xm_surface_alloc;
|
ws->surface_alloc = xm_surface_alloc;
|
||||||
ws->surface_alloc_storage = xm_surface_alloc_storage;
|
ws->surface_alloc_storage = xm_surface_alloc_storage;
|
||||||
|
@@ -101,7 +101,7 @@ static void *aub_buffer_map(struct pipe_winsys *winsys,
|
|||||||
|
|
||||||
assert(sbo->data);
|
assert(sbo->data);
|
||||||
|
|
||||||
if (flags & PIPE_BUFFER_FLAG_WRITE)
|
if (flags & PIPE_BUFFER_USAGE_CPU_WRITE)
|
||||||
sbo->dump_on_unmap = 1;
|
sbo->dump_on_unmap = 1;
|
||||||
|
|
||||||
sbo->map_count++;
|
sbo->map_count++;
|
||||||
@@ -150,61 +150,6 @@ aub_buffer_reference(struct pipe_winsys *winsys,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int aub_buffer_data(struct pipe_winsys *winsys,
|
|
||||||
struct pipe_buffer_handle *buf,
|
|
||||||
unsigned size, const void *data,
|
|
||||||
unsigned usage )
|
|
||||||
{
|
|
||||||
struct aub_pipe_winsys *iws = aub_pipe_winsys(winsys);
|
|
||||||
struct aub_buffer *sbo = aub_bo(buf);
|
|
||||||
|
|
||||||
/* Could reuse buffers that are not referenced in current
|
|
||||||
* batchbuffer. Can't do that atm, so always reallocate:
|
|
||||||
*/
|
|
||||||
if (1 || sbo->size < size) {
|
|
||||||
assert(iws->used + size < iws->size);
|
|
||||||
sbo->data = iws->pool + iws->used;
|
|
||||||
sbo->offset = AUB_BUF_START + iws->used;
|
|
||||||
iws->used += align(size, 4096);
|
|
||||||
}
|
|
||||||
|
|
||||||
sbo->size = size;
|
|
||||||
|
|
||||||
if (data != NULL) {
|
|
||||||
memcpy(sbo->data, data, size);
|
|
||||||
|
|
||||||
brw_aub_gtt_data( iws->aubfile,
|
|
||||||
sbo->offset,
|
|
||||||
sbo->data,
|
|
||||||
sbo->size,
|
|
||||||
0,
|
|
||||||
0 );
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int aub_buffer_subdata(struct pipe_winsys *winsys,
|
|
||||||
struct pipe_buffer_handle *buf,
|
|
||||||
unsigned long offset,
|
|
||||||
unsigned long size,
|
|
||||||
const void *data)
|
|
||||||
{
|
|
||||||
struct aub_pipe_winsys *iws = aub_pipe_winsys(winsys);
|
|
||||||
struct aub_buffer *sbo = aub_bo(buf);
|
|
||||||
|
|
||||||
assert(sbo->size > offset + size);
|
|
||||||
memcpy(sbo->data + offset, data, size);
|
|
||||||
|
|
||||||
brw_aub_gtt_data( iws->aubfile,
|
|
||||||
sbo->offset + offset,
|
|
||||||
sbo->data + offset,
|
|
||||||
size,
|
|
||||||
0,
|
|
||||||
0 );
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void xmesa_buffer_subdata_aub(struct pipe_winsys *winsys,
|
void xmesa_buffer_subdata_aub(struct pipe_winsys *winsys,
|
||||||
struct pipe_buffer_handle *buf,
|
struct pipe_buffer_handle *buf,
|
||||||
unsigned long offset,
|
unsigned long offset,
|
||||||
@@ -258,29 +203,30 @@ void xmesa_display_aub( /* struct pipe_winsys *winsys, */
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
static int aub_buffer_get_subdata(struct pipe_winsys *winsys,
|
|
||||||
struct pipe_buffer_handle *buf,
|
|
||||||
unsigned long offset,
|
|
||||||
unsigned long size,
|
|
||||||
void *data)
|
|
||||||
{
|
|
||||||
struct aub_buffer *sbo = aub_bo(buf);
|
|
||||||
assert(sbo->size >= offset + size);
|
|
||||||
memcpy(data, sbo->data + offset, size);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Pipe has no concept of pools. We choose the tex/region pool
|
/* Pipe has no concept of pools. We choose the tex/region pool
|
||||||
* for all buffers.
|
* for all buffers.
|
||||||
*/
|
*/
|
||||||
static struct pipe_buffer_handle *
|
static struct pipe_buffer_handle *
|
||||||
aub_buffer_create(struct pipe_winsys *winsys,
|
aub_buffer_create(struct pipe_winsys *winsys,
|
||||||
unsigned alignment,
|
unsigned alignment,
|
||||||
unsigned flags,
|
unsigned usage,
|
||||||
unsigned hint)
|
unsigned size)
|
||||||
{
|
{
|
||||||
|
struct aub_pipe_winsys *iws = aub_pipe_winsys(winsys);
|
||||||
struct aub_buffer *sbo = CALLOC_STRUCT(aub_buffer);
|
struct aub_buffer *sbo = CALLOC_STRUCT(aub_buffer);
|
||||||
|
|
||||||
sbo->refcount = 1;
|
sbo->refcount = 1;
|
||||||
|
|
||||||
|
/* Could reuse buffers that are not referenced in current
|
||||||
|
* batchbuffer. Can't do that atm, so always reallocate:
|
||||||
|
*/
|
||||||
|
assert(iws->used + size < iws->size);
|
||||||
|
sbo->data = iws->pool + iws->used;
|
||||||
|
sbo->offset = AUB_BUF_START + iws->used;
|
||||||
|
iws->used += align(size, 4096);
|
||||||
|
|
||||||
|
sbo->size = size;
|
||||||
|
|
||||||
return pipe_bo(sbo);
|
return pipe_bo(sbo);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -288,17 +234,14 @@ aub_buffer_create(struct pipe_winsys *winsys,
|
|||||||
static struct pipe_buffer_handle *
|
static struct pipe_buffer_handle *
|
||||||
aub_user_buffer_create(struct pipe_winsys *winsys, void *ptr, unsigned bytes)
|
aub_user_buffer_create(struct pipe_winsys *winsys, void *ptr, unsigned bytes)
|
||||||
{
|
{
|
||||||
struct aub_buffer *sbo = CALLOC_STRUCT(aub_buffer);
|
struct aub_buffer *sbo;
|
||||||
|
|
||||||
sbo->refcount = 1;
|
|
||||||
|
|
||||||
/* Lets hope this is meant for upload, not as a result!
|
/* Lets hope this is meant for upload, not as a result!
|
||||||
*/
|
*/
|
||||||
aub_buffer_data( winsys,
|
sbo = aub_bo(aub_buffer_create( winsys, 0, 0, 0 ));
|
||||||
pipe_bo(sbo),
|
|
||||||
bytes,
|
sbo->data = ptr;
|
||||||
ptr,
|
sbo->size = bytes;
|
||||||
0 );
|
|
||||||
|
|
||||||
return pipe_bo(sbo);
|
return pipe_bo(sbo);
|
||||||
}
|
}
|
||||||
@@ -345,7 +288,6 @@ aub_i915_surface_alloc_storage(struct pipe_winsys *winsys,
|
|||||||
unsigned flags)
|
unsigned flags)
|
||||||
{
|
{
|
||||||
const unsigned alignment = 64;
|
const unsigned alignment = 64;
|
||||||
int ret;
|
|
||||||
|
|
||||||
surf->width = width;
|
surf->width = width;
|
||||||
surf->height = height;
|
surf->height = height;
|
||||||
@@ -354,20 +296,12 @@ aub_i915_surface_alloc_storage(struct pipe_winsys *winsys,
|
|||||||
surf->pitch = round_up(width, alignment / surf->cpp);
|
surf->pitch = round_up(width, alignment / surf->cpp);
|
||||||
|
|
||||||
assert(!surf->buffer);
|
assert(!surf->buffer);
|
||||||
surf->buffer = winsys->buffer_create(winsys, alignment, 0, 0);
|
surf->buffer = winsys->buffer_create(winsys, alignment,
|
||||||
|
PIPE_BUFFER_USAGE_PIXEL,
|
||||||
|
surf->pitch * surf->cpp * height);
|
||||||
if(!surf->buffer)
|
if(!surf->buffer)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
ret = winsys->buffer_data(winsys,
|
|
||||||
surf->buffer,
|
|
||||||
surf->pitch * surf->cpp * height,
|
|
||||||
NULL,
|
|
||||||
0);
|
|
||||||
if(ret) {
|
|
||||||
winsys->buffer_reference(winsys, &surf->buffer, NULL);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -418,9 +352,6 @@ xmesa_create_pipe_winsys_aub( void )
|
|||||||
iws->winsys.buffer_map = aub_buffer_map;
|
iws->winsys.buffer_map = aub_buffer_map;
|
||||||
iws->winsys.buffer_unmap = aub_buffer_unmap;
|
iws->winsys.buffer_unmap = aub_buffer_unmap;
|
||||||
iws->winsys.buffer_reference = aub_buffer_reference;
|
iws->winsys.buffer_reference = aub_buffer_reference;
|
||||||
iws->winsys.buffer_data = aub_buffer_data;
|
|
||||||
iws->winsys.buffer_subdata = aub_buffer_subdata;
|
|
||||||
iws->winsys.buffer_get_subdata = aub_buffer_get_subdata;
|
|
||||||
iws->winsys.flush_frontbuffer = aub_flush_frontbuffer;
|
iws->winsys.flush_frontbuffer = aub_flush_frontbuffer;
|
||||||
iws->winsys.printf = aub_printf;
|
iws->winsys.printf = aub_printf;
|
||||||
iws->winsys.get_name = aub_get_name;
|
iws->winsys.get_name = aub_get_name;
|
||||||
|
@@ -69,8 +69,13 @@ void st_upload_constants( struct st_context *st,
|
|||||||
|
|
||||||
_mesa_load_state_parameters(st->ctx, params);
|
_mesa_load_state_parameters(st->ctx, params);
|
||||||
|
|
||||||
if (!cbuf->buffer)
|
if (cbuf->buffer && cbuf->size != paramBytes)
|
||||||
cbuf->buffer = ws->buffer_create(ws, 1, 0, 0);
|
ws->buffer_reference( ws, &cbuf->buffer, NULL );
|
||||||
|
|
||||||
|
if (!cbuf->buffer) {
|
||||||
|
cbuf->buffer = ws->buffer_create(ws, 1, PIPE_BUFFER_USAGE_CONSTANT,
|
||||||
|
paramBytes);
|
||||||
|
}
|
||||||
|
|
||||||
if (0)
|
if (0)
|
||||||
{
|
{
|
||||||
@@ -80,8 +85,11 @@ void st_upload_constants( struct st_context *st,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* load Mesa constants into the constant buffer */
|
/* load Mesa constants into the constant buffer */
|
||||||
ws->buffer_data(ws, cbuf->buffer, paramBytes, params->ParameterValues,
|
if (cbuf->buffer) {
|
||||||
PIPE_BUFFER_USAGE_CONSTANT);
|
memcpy(ws->buffer_map(ws, cbuf->buffer, PIPE_BUFFER_USAGE_CPU_WRITE),
|
||||||
|
params->ParameterValues, paramBytes);
|
||||||
|
ws->buffer_unmap(ws, cbuf->buffer);
|
||||||
|
}
|
||||||
|
|
||||||
cbuf->size = paramBytes;
|
cbuf->size = paramBytes;
|
||||||
|
|
||||||
|
@@ -55,7 +55,6 @@
|
|||||||
static struct gl_buffer_object *
|
static struct gl_buffer_object *
|
||||||
st_bufferobj_alloc(GLcontext *ctx, GLuint name, GLenum target)
|
st_bufferobj_alloc(GLcontext *ctx, GLuint name, GLenum target)
|
||||||
{
|
{
|
||||||
struct st_context *st = st_context(ctx);
|
|
||||||
struct st_buffer_object *st_obj = CALLOC_STRUCT(st_buffer_object);
|
struct st_buffer_object *st_obj = CALLOC_STRUCT(st_buffer_object);
|
||||||
|
|
||||||
if (!st_obj)
|
if (!st_obj)
|
||||||
@@ -63,8 +62,6 @@ st_bufferobj_alloc(GLcontext *ctx, GLuint name, GLenum target)
|
|||||||
|
|
||||||
_mesa_initialize_buffer_object(&st_obj->Base, name, target);
|
_mesa_initialize_buffer_object(&st_obj->Base, name, target);
|
||||||
|
|
||||||
st_obj->buffer = st->pipe->winsys->buffer_create( st->pipe->winsys, 32, 0, 0 );
|
|
||||||
|
|
||||||
return &st_obj->Base;
|
return &st_obj->Base;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,6 +85,57 @@ st_bufferobj_free(GLcontext *ctx, struct gl_buffer_object *obj)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replace data in a subrange of buffer object. If the data range
|
||||||
|
* specified by size + offset extends beyond the end of the buffer or
|
||||||
|
* if data is NULL, no copy is performed.
|
||||||
|
* Called via glBufferSubDataARB().
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
st_bufferobj_subdata(GLcontext *ctx,
|
||||||
|
GLenum target,
|
||||||
|
GLintptrARB offset,
|
||||||
|
GLsizeiptrARB size,
|
||||||
|
const GLvoid * data, struct gl_buffer_object *obj)
|
||||||
|
{
|
||||||
|
struct pipe_context *pipe = st_context(ctx)->pipe;
|
||||||
|
struct st_buffer_object *st_obj = st_buffer_object(obj);
|
||||||
|
char *map;
|
||||||
|
|
||||||
|
if (offset >= st_obj->size || size > (st_obj->size - offset))
|
||||||
|
return;
|
||||||
|
|
||||||
|
map = pipe->winsys->buffer_map(pipe->winsys, st_obj->buffer,
|
||||||
|
PIPE_BUFFER_USAGE_CPU_WRITE);
|
||||||
|
memcpy(map + offset, data, size);
|
||||||
|
pipe->winsys->buffer_unmap(pipe->winsys, st_obj->buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called via glGetBufferSubDataARB().
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
st_bufferobj_get_subdata(GLcontext *ctx,
|
||||||
|
GLenum target,
|
||||||
|
GLintptrARB offset,
|
||||||
|
GLsizeiptrARB size,
|
||||||
|
GLvoid * data, struct gl_buffer_object *obj)
|
||||||
|
{
|
||||||
|
struct pipe_context *pipe = st_context(ctx)->pipe;
|
||||||
|
struct st_buffer_object *st_obj = st_buffer_object(obj);
|
||||||
|
char *map;
|
||||||
|
|
||||||
|
if (offset >= st_obj->size || size > (st_obj->size - offset))
|
||||||
|
return;
|
||||||
|
|
||||||
|
map = pipe->winsys->buffer_map(pipe->winsys, st_obj->buffer,
|
||||||
|
PIPE_BUFFER_USAGE_CPU_READ);
|
||||||
|
memcpy(data, map + offset, size);
|
||||||
|
pipe->winsys->buffer_unmap(pipe->winsys, st_obj->buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allocate space for and store data in a buffer object. Any data that was
|
* Allocate space for and store data in a buffer object. Any data that was
|
||||||
* previously stored in the buffer object is lost. If data is NULL,
|
* previously stored in the buffer object is lost. If data is NULL,
|
||||||
@@ -102,7 +150,8 @@ st_bufferobj_data(GLcontext *ctx,
|
|||||||
GLenum usage,
|
GLenum usage,
|
||||||
struct gl_buffer_object *obj)
|
struct gl_buffer_object *obj)
|
||||||
{
|
{
|
||||||
struct pipe_context *pipe = st_context(ctx)->pipe;
|
struct st_context *st = st_context(ctx);
|
||||||
|
struct pipe_context *pipe = st->pipe;
|
||||||
struct st_buffer_object *st_obj = st_buffer_object(obj);
|
struct st_buffer_object *st_obj = st_buffer_object(obj);
|
||||||
unsigned buffer_usage;
|
unsigned buffer_usage;
|
||||||
|
|
||||||
@@ -124,46 +173,15 @@ st_bufferobj_data(GLcontext *ctx,
|
|||||||
buffer_usage = 0;
|
buffer_usage = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
pipe->winsys->buffer_data( pipe->winsys, st_obj->buffer,
|
pipe->winsys->buffer_reference( pipe->winsys, &st_obj->buffer, NULL );
|
||||||
size, data,
|
|
||||||
buffer_usage );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
st_obj->buffer = pipe->winsys->buffer_create( pipe->winsys, 32, buffer_usage,
|
||||||
|
size );
|
||||||
|
|
||||||
/**
|
st_obj->size = size;
|
||||||
* Replace data in a subrange of buffer object. If the data range
|
|
||||||
* specified by size + offset extends beyond the end of the buffer or
|
|
||||||
* if data is NULL, no copy is performed.
|
|
||||||
* Called via glBufferSubDataARB().
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
st_bufferobj_subdata(GLcontext *ctx,
|
|
||||||
GLenum target,
|
|
||||||
GLintptrARB offset,
|
|
||||||
GLsizeiptrARB size,
|
|
||||||
const GLvoid * data, struct gl_buffer_object *obj)
|
|
||||||
{
|
|
||||||
struct pipe_context *pipe = st_context(ctx)->pipe;
|
|
||||||
struct st_buffer_object *st_obj = st_buffer_object(obj);
|
|
||||||
|
|
||||||
pipe->winsys->buffer_subdata(pipe->winsys, st_obj->buffer, offset, size, data);
|
if (data)
|
||||||
}
|
st_bufferobj_subdata(ctx, target, 0, size, data, obj);
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called via glGetBufferSubDataARB().
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
st_bufferobj_get_subdata(GLcontext *ctx,
|
|
||||||
GLenum target,
|
|
||||||
GLintptrARB offset,
|
|
||||||
GLsizeiptrARB size,
|
|
||||||
GLvoid * data, struct gl_buffer_object *obj)
|
|
||||||
{
|
|
||||||
struct pipe_context *pipe = st_context(ctx)->pipe;
|
|
||||||
struct st_buffer_object *st_obj = st_buffer_object(obj);
|
|
||||||
|
|
||||||
pipe->winsys->buffer_get_subdata(pipe->winsys, st_obj->buffer, offset, size, data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -180,15 +198,15 @@ st_bufferobj_map(GLcontext *ctx, GLenum target, GLenum access,
|
|||||||
|
|
||||||
switch (access) {
|
switch (access) {
|
||||||
case GL_WRITE_ONLY:
|
case GL_WRITE_ONLY:
|
||||||
flags = PIPE_BUFFER_FLAG_WRITE;
|
flags = PIPE_BUFFER_USAGE_CPU_WRITE;
|
||||||
break;
|
break;
|
||||||
case GL_READ_ONLY:
|
case GL_READ_ONLY:
|
||||||
flags = PIPE_BUFFER_FLAG_READ;
|
flags = PIPE_BUFFER_USAGE_CPU_READ;
|
||||||
break;
|
break;
|
||||||
case GL_READ_WRITE:
|
case GL_READ_WRITE:
|
||||||
/* fall-through */
|
/* fall-through */
|
||||||
default:
|
default:
|
||||||
flags = PIPE_BUFFER_FLAG_READ | PIPE_BUFFER_FLAG_WRITE;
|
flags = PIPE_BUFFER_USAGE_CPU_READ | PIPE_BUFFER_USAGE_CPU_WRITE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -40,6 +40,7 @@ struct st_buffer_object
|
|||||||
{
|
{
|
||||||
struct gl_buffer_object Base;
|
struct gl_buffer_object Base;
|
||||||
struct pipe_buffer_handle *buffer;
|
struct pipe_buffer_handle *buffer;
|
||||||
|
GLsizeiptrARB size;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@@ -164,13 +164,6 @@ struct st_context
|
|||||||
struct st_fragment_program *combined_prog;
|
struct st_fragment_program *combined_prog;
|
||||||
} bitmap;
|
} bitmap;
|
||||||
|
|
||||||
/**
|
|
||||||
* Buffer object which stores the ctx->Current.Attrib[] values.
|
|
||||||
* Used for vertex array drawing when we we need an attribute for
|
|
||||||
* which there's no enabled array.
|
|
||||||
*/
|
|
||||||
struct pipe_buffer_handle *default_attrib_buffer;
|
|
||||||
|
|
||||||
struct cso_cache *cache;
|
struct cso_cache *cache;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -190,29 +190,6 @@ pipe_vertex_format(GLenum type, GLuint size, GLboolean normalized)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The default attribute buffer is basically a copy of the
|
|
||||||
* ctx->Current.Attrib[] array. It's used when the vertex program
|
|
||||||
* references an attribute for which we don't have a VBO/array.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
create_default_attribs_buffer(struct st_context *st)
|
|
||||||
{
|
|
||||||
struct pipe_context *pipe = st->pipe;
|
|
||||||
/* XXX don't hardcode magic 32 here */
|
|
||||||
st->default_attrib_buffer = pipe->winsys->buffer_create( pipe->winsys, 32, 0, 0 );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
destroy_default_attribs_buffer(struct st_context *st)
|
|
||||||
{
|
|
||||||
struct pipe_context *pipe = st->pipe;
|
|
||||||
pipe->winsys->buffer_reference(pipe->winsys,
|
|
||||||
&st->default_attrib_buffer, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This function gets plugged into the VBO module and is called when
|
* This function gets plugged into the VBO module and is called when
|
||||||
* we have something to render.
|
* we have something to render.
|
||||||
@@ -399,10 +376,14 @@ st_draw_vertices(GLcontext *ctx, unsigned prim,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* XXX create one-time */
|
/* XXX create one-time */
|
||||||
vbuf = pipe->winsys->buffer_create(pipe->winsys, 32, 0, 0);
|
vbuf = pipe->winsys->buffer_create(pipe->winsys, 32,
|
||||||
pipe->winsys->buffer_data(pipe->winsys, vbuf,
|
PIPE_BUFFER_USAGE_VERTEX, vertex_bytes);
|
||||||
vertex_bytes, verts,
|
assert(vbuf);
|
||||||
PIPE_BUFFER_USAGE_VERTEX);
|
|
||||||
|
memcpy(pipe->winsys->buffer_map(pipe->winsys, vbuf,
|
||||||
|
PIPE_BUFFER_USAGE_CPU_WRITE),
|
||||||
|
verts, vertex_bytes);
|
||||||
|
pipe->winsys->buffer_unmap(pipe->winsys, vbuf);
|
||||||
|
|
||||||
/* tell pipe about the vertex buffer */
|
/* tell pipe about the vertex buffer */
|
||||||
vbuffer.buffer = vbuf;
|
vbuffer.buffer = vbuf;
|
||||||
@@ -568,7 +549,7 @@ st_feedback_draw_vbo(GLcontext *ctx,
|
|||||||
/* map the attrib buffer */
|
/* map the attrib buffer */
|
||||||
map = pipe->winsys->buffer_map(pipe->winsys,
|
map = pipe->winsys->buffer_map(pipe->winsys,
|
||||||
vbuffer[attr].buffer,
|
vbuffer[attr].buffer,
|
||||||
PIPE_BUFFER_FLAG_READ);
|
PIPE_BUFFER_USAGE_CPU_READ);
|
||||||
draw_set_mapped_vertex_buffer(draw, attr, map);
|
draw_set_mapped_vertex_buffer(draw, attr, map);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -592,7 +573,7 @@ st_feedback_draw_vbo(GLcontext *ctx,
|
|||||||
|
|
||||||
map = pipe->winsys->buffer_map(pipe->winsys,
|
map = pipe->winsys->buffer_map(pipe->winsys,
|
||||||
index_buffer_handle,
|
index_buffer_handle,
|
||||||
PIPE_BUFFER_FLAG_READ);
|
PIPE_BUFFER_USAGE_CPU_READ);
|
||||||
draw_set_mapped_element_buffer(draw, indexSize, map);
|
draw_set_mapped_element_buffer(draw, indexSize, map);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -604,7 +585,7 @@ st_feedback_draw_vbo(GLcontext *ctx,
|
|||||||
/* map constant buffers */
|
/* map constant buffers */
|
||||||
mapped_constants = winsys->buffer_map(winsys,
|
mapped_constants = winsys->buffer_map(winsys,
|
||||||
st->state.constants[PIPE_SHADER_VERTEX].buffer,
|
st->state.constants[PIPE_SHADER_VERTEX].buffer,
|
||||||
PIPE_BUFFER_FLAG_READ);
|
PIPE_BUFFER_USAGE_CPU_READ);
|
||||||
draw_set_mapped_constant_buffer(st->draw, mapped_constants);
|
draw_set_mapped_constant_buffer(st->draw, mapped_constants);
|
||||||
|
|
||||||
|
|
||||||
@@ -640,16 +621,12 @@ void st_init_draw( struct st_context *st )
|
|||||||
{
|
{
|
||||||
GLcontext *ctx = st->ctx;
|
GLcontext *ctx = st->ctx;
|
||||||
|
|
||||||
/* actually, not used here, but elsewhere */
|
|
||||||
create_default_attribs_buffer(st);
|
|
||||||
|
|
||||||
vbo_set_draw_func(ctx, st_draw_vbo);
|
vbo_set_draw_func(ctx, st_draw_vbo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void st_destroy_draw( struct st_context *st )
|
void st_destroy_draw( struct st_context *st )
|
||||||
{
|
{
|
||||||
destroy_default_attribs_buffer(st);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user