Commit a45bd509 authored by Roland Scheidegger's avatar Roland Scheidegger

Merge remote branch 'origin/master' into gallium-array-textures

Conflicts:
	src/gallium/drivers/i915/i915_resource_texture.c
	src/gallium/drivers/i915/i915_state_emit.c
	src/gallium/drivers/i915/i915_surface.c
parents 1aeca287 32e1e591
Random list of problems with i915g:
- Dies with BadDrawable on GLXFBconfig changes/destruction. Makes piglit totally
unusable :( Upgrading xserver helped here, it doesn't crash anymore. Still
broken, it doesn't update the viewport/get new buffers.
- Tends to hang the chip after a few minutes of openarena. Looks tiling related,
at the last frame rendered has tiling corruption over the complete frame.
- Kills the chip in 3D_PRIMITIVE LINELIST with mesa-demos/fbotexture in
wireframe mode.
- Tiling is funny: If unlucky, it renders/samples all black. No clue yet what's
going on. Seems to depend on tiny details like whethever the sampler
relocation is fenced/unfenced (broken _with_ fenced reloc using tiling bits!).
- Y-tiling is even more fun. i915c doesn't use it, maybe there's a reason?
Texture sampling from Y-tiled buffers seems to work, though (save above
problems).
- Need to validate buffers before usage. Currently do_exec on the batchbuffer
can fail with -ENOSPC.
Other bugs can be found here:
https://bugs.freedesktop.org/buglist.cgi?bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&component=Drivers/Gallium/i915g
......@@ -38,7 +38,10 @@
i915_winsys_batchbuffer_dword(i915->batch, dword)
#define OUT_RELOC(buf, usage, offset) \
i915_winsys_batchbuffer_reloc(i915->batch, buf, usage, offset)
i915_winsys_batchbuffer_reloc(i915->batch, buf, usage, offset, false)
#define OUT_RELOC_FENCED(buf, usage, offset) \
i915_winsys_batchbuffer_reloc(i915->batch, buf, usage, offset, true)
#define FLUSH_BATCH(fence) \
i915_flush(i915, fence)
......
......@@ -29,42 +29,47 @@
#define I915_BATCHBUFFER_H
#include "i915_winsys.h"
#include "util/u_debug.h"
struct i915_context;
static INLINE size_t
i915_winsys_batchbuffer_space(struct i915_winsys_batchbuffer *batch)
{
return batch->size - (batch->ptr - batch->map);
}
static INLINE boolean
i915_winsys_batchbuffer_check(struct i915_winsys_batchbuffer *batch,
size_t dwords,
size_t relocs)
{
return dwords * 4 <= batch->size - (batch->ptr - batch->map) &&
return dwords * 4 <= i915_winsys_batchbuffer_space(batch) &&
relocs <= (batch->max_relocs - batch->relocs);
}
static INLINE size_t
i915_winsys_batchbuffer_space(struct i915_winsys_batchbuffer *batch)
static INLINE void
i915_winsys_batchbuffer_dword_unchecked(struct i915_winsys_batchbuffer *batch,
unsigned dword)
{
return batch->size - (batch->ptr - batch->map);
*(unsigned *)batch->ptr = dword;
batch->ptr += 4;
}
static INLINE void
i915_winsys_batchbuffer_dword(struct i915_winsys_batchbuffer *batch,
unsigned dword)
{
if (i915_winsys_batchbuffer_space(batch) < 4)
return;
*(unsigned *)batch->ptr = dword;
batch->ptr += 4;
assert (i915_winsys_batchbuffer_space(batch) >= 4);
i915_winsys_batchbuffer_dword_unchecked(batch, dword);
}
static INLINE void
i915_winsys_batchbuffer_write(struct i915_winsys_batchbuffer *batch,
void *data,
size_t size)
void *data,
size_t size)
{
if (i915_winsys_batchbuffer_space(batch) < size)
return;
assert (i915_winsys_batchbuffer_space(batch) >= size);
memcpy(data, batch->ptr, size);
batch->ptr += size;
......@@ -74,9 +79,9 @@ static INLINE int
i915_winsys_batchbuffer_reloc(struct i915_winsys_batchbuffer *batch,
struct i915_winsys_buffer *buffer,
enum i915_winsys_buffer_usage usage,
size_t offset)
size_t offset, bool fenced)
{
return batch->iws->batchbuffer_reloc(batch, buffer, usage, offset);
return batch->iws->batchbuffer_reloc(batch, buffer, usage, offset, fenced);
}
#endif
......@@ -74,7 +74,7 @@ i915_fill_blit(struct i915_context *i915,
OUT_BATCH(BR13);
OUT_BATCH((y << 16) | x);
OUT_BATCH(((y + h) << 16) | (x + w));
OUT_RELOC(dst_buffer, I915_USAGE_2D_TARGET, dst_offset);
OUT_RELOC_FENCED(dst_buffer, I915_USAGE_2D_TARGET, dst_offset);
OUT_BATCH(color);
}
......@@ -138,8 +138,8 @@ i915_copy_blit(struct i915_context *i915,
OUT_BATCH(BR13);
OUT_BATCH((dst_y << 16) | dst_x);
OUT_BATCH((dst_y2 << 16) | dst_x2);
OUT_RELOC(dst_buffer, I915_USAGE_2D_TARGET, dst_offset);
OUT_RELOC_FENCED(dst_buffer, I915_USAGE_2D_TARGET, dst_offset);
OUT_BATCH((src_y << 16) | src_x);
OUT_BATCH(((int) src_pitch & 0xffff));
OUT_RELOC(src_buffer, I915_USAGE_2D_SOURCE, src_offset);
OUT_RELOC_FENCED(src_buffer, I915_USAGE_2D_SOURCE, src_offset);
}
......@@ -193,8 +193,7 @@ struct i915_velems_state {
};
struct i915_context
{
struct i915_context {
struct pipe_context base;
struct i915_winsys *iws;
......
......@@ -46,10 +46,12 @@ static const struct debug_named_value debug_options[] = {
};
unsigned i915_debug = 0;
boolean i915_tiling = TRUE;
void i915_debug_init(struct i915_screen *screen)
{
i915_debug = debug_get_flags_option("I915_DEBUG", debug_options, 0);
i915_tiling = !debug_get_bool_option("I915_NO_TILING", FALSE);
}
......
......@@ -46,6 +46,7 @@ struct i915_winsys_batchbuffer;
#define DBG_CONSTANTS 0x20
extern unsigned i915_debug;
extern boolean i915_tiling;
#ifdef DEBUG
static INLINE boolean
......
......@@ -172,6 +172,7 @@ i915_vbuf_render_reserve(struct i915_vbuf_render *i915_render, size_t size)
*
* Side effects:
* Updates hw_offset, sw_offset, index and allocates a new buffer.
* Will set i915->vbo to null on buffer allocation.
*/
static void
i915_vbuf_render_new_buf(struct i915_vbuf_render *i915_render, size_t size)
......@@ -179,8 +180,16 @@ i915_vbuf_render_new_buf(struct i915_vbuf_render *i915_render, size_t size)
struct i915_context *i915 = i915_render->i915;
struct i915_winsys *iws = i915->iws;
if (i915_render->vbo)
if (i915_render->vbo) {
iws->buffer_destroy(iws, i915_render->vbo);
/*
* XXX If buffers where referenced then this should be done in
* update_vbo_state but since they arn't and malloc likes to reuse
* memory we need to set it to null
*/
i915->vbo = NULL;
i915_render->vbo = NULL;
}
i915->vbo_flushed = 0;
......@@ -198,7 +207,7 @@ i915_vbuf_render_new_buf(struct i915_vbuf_render *i915_render, size_t size)
#endif
i915_render->vbo = iws->buffer_create(iws, i915_render->vbo_size,
64, I915_NEW_VERTEX);
I915_NEW_VERTEX);
}
/**
......@@ -726,7 +735,7 @@ i915_vbuf_render_create(struct i915_context *i915)
i915_render->pool_fifo = u_fifo_create(6);
for (i = 0; i < 6; i++)
u_fifo_add(i915_render->pool_fifo,
iws->buffer_create(iws, i915_render->pool_buffer_size, 64,
iws->buffer_create(iws, i915_render->pool_buffer_size,
I915_NEW_VERTEX));
#else
(void)i;
......
......@@ -753,7 +753,7 @@
#define MT_COMPRESS_DXT1_RGB (4<<3)
#define MS3_USE_FENCE_REGS (1<<2)
#define MS3_TILED_SURFACE (1<<1)
#define MS3_TILE_WALK (1<<0)
#define MS3_TILE_WALK_Y (1<<0)
#define MS4_PITCH_SHIFT 21
#define MS4_CUBE_FACE_ENA_NEGX (1<<20)
......@@ -851,6 +851,7 @@
#define MI_FLUSH ((0<<29)|(4<<23))
#define FLUSH_MAP_CACHE (1<<0)
#define INHIBIT_FLUSH_RENDER_CACHE (1<<2)
#define MI_NOOP 0
#define CMD_3D (0x3<<29)
......
......@@ -49,6 +49,10 @@ struct i915_buffer {
#define I915_MAX_TEXTURE_3D_LEVELS 8 /* max 128x128x128 */
struct offset_pair {
unsigned short nblocksx;
unsigned short nblocksy;
};
struct i915_texture {
struct u_resource b;
......@@ -63,14 +67,18 @@ struct i915_texture {
/* Explicitly store the offset of each image for each cube face or
* depth value.
*
* Array [depth] off offsets.
*/
unsigned *image_offset[I915_MAX_TEXTURE_2D_LEVELS]; /**< array [depth] of offsets */
struct offset_pair *image_offset[I915_MAX_TEXTURE_2D_LEVELS];
/* The data is held here:
*/
struct i915_winsys_buffer *buffer;
};
unsigned i915_texture_offset(struct i915_texture *tex,
unsigned level, unsigned layer);
void i915_init_screen_resource_functions(struct i915_screen *is);
void i915_init_resource_functions(struct i915_context *i915);
......
......@@ -106,6 +106,23 @@ get_pot_stride(enum pipe_format format, unsigned width)
return util_next_power_of_two(util_format_get_stride(format, width));
}
static INLINE const char*
get_tiling_string(enum i915_winsys_buffer_tile tile)
{
switch(tile) {
case I915_TILE_NONE:
return "none";
case I915_TILE_X:
return "x";
case I915_TILE_Y:
return "y";
default:
assert(FALSE);
return "?";
}
}
/*
* More advanced helper funcs
*/
......@@ -120,28 +137,56 @@ i915_texture_set_level_info(struct i915_texture *tex,
assert(!tex->image_offset[level]);
tex->nr_images[level] = nr_images;
tex->image_offset[level] = (unsigned *) MALLOC(nr_images * sizeof(unsigned));
tex->image_offset[level][0] = 0;
tex->image_offset[level] = MALLOC(nr_images * sizeof(struct offset_pair));
tex->image_offset[level][0].nblocksx = 0;
tex->image_offset[level][0].nblocksy = 0;
}
INLINE unsigned i915_texture_offset(struct i915_texture *tex,
unsigned level, unsigned layer)
{
unsigned x, y;
x = tex->image_offset[level][layer].nblocksx
* util_format_get_blocksize(tex->b.b.format);
y = tex->image_offset[level][layer].nblocksy;
return y * tex->stride + x;
}
static void
i915_texture_set_image_offset(struct i915_texture *tex,
unsigned level, unsigned img,
unsigned x, unsigned y)
unsigned nblocksx, unsigned nblocksy)
{
/* for the first image and level make sure offset is zero */
assert(!(img == 0 && level == 0) || (x == 0 && y == 0));
assert(!(img == 0 && level == 0) || (nblocksx == 0 && nblocksy == 0));
assert(img < tex->nr_images[level]);
tex->image_offset[level][img] = y * tex->stride + x * util_format_get_blocksize(tex->b.b.format);
tex->image_offset[level][img].nblocksx = nblocksx;
tex->image_offset[level][img].nblocksy = nblocksy;
#if DEBUG_TEXTURES
debug_printf("%s: %p level %u, img %u (%u, %u) %p\n", __FUNCTION__,
tex, level, img, x, y,
(void*)(uintptr_t)tex->image_offset[level][img]);
debug_printf("%s: %p level %u, img %u (%u, %u)\n", __FUNCTION__,
tex, level, img, x, y);
#endif
}
static enum i915_winsys_buffer_tile
i915_texture_tiling(struct pipe_resource *pt)
{
if (!i915_tiling)
return I915_TILE_NONE;
if (pt->target == PIPE_TEXTURE_1D)
return I915_TILE_NONE;
if (util_format_is_s3tc(pt->format))
/* XXX X-tiling might make sense */
return I915_TILE_NONE;
return I915_TILE_X;
}
/*
* Shared layout functions
......@@ -163,9 +208,10 @@ i9x5_scanout_layout(struct i915_texture *tex)
i915_texture_set_image_offset(tex, 0, 0, 0, 0);
if (pt->width0 >= 240) {
tex->stride = get_pot_stride(pt->format, pt->width0);
tex->stride = align(util_format_get_stride(pt->format, pt->width0), 64);
tex->total_nblocksy = align_nblocksy(pt->format, pt->height0, 8);
tex->tiling = I915_TILE_X;
/* special case for cursors */
} else if (pt->width0 == 64 && pt->height0 == 64) {
tex->stride = get_pot_stride(pt->format, pt->width0);
tex->total_nblocksy = align_nblocksy(pt->format, pt->height0, 8);
......@@ -200,7 +246,7 @@ i9x5_display_target_layout(struct i915_texture *tex)
i915_texture_set_level_info(tex, 0, 1);
i915_texture_set_image_offset(tex, 0, 0, 0, 0);
tex->stride = get_pot_stride(pt->format, pt->width0);
tex->stride = align(util_format_get_stride(pt->format, pt->width0), 64);
tex->total_nblocksy = align_nblocksy(pt->format, pt->height0, 8);
tex->tiling = I915_TILE_X;
......@@ -357,6 +403,8 @@ i915_texture_layout(struct i915_texture * tex)
{
struct pipe_resource *pt = &tex->b.b;
tex->tiling = i915_texture_tiling(pt);
switch (pt->target) {
case PIPE_TEXTURE_1D:
case PIPE_TEXTURE_2D:
......@@ -603,6 +651,8 @@ i945_texture_layout(struct i915_texture * tex)
{
struct pipe_resource *pt = &tex->b.b;
tex->tiling = i915_texture_tiling(pt);
switch (pt->target) {
case PIPE_TEXTURE_1D:
case PIPE_TEXTURE_2D:
......@@ -687,7 +737,6 @@ i915_texture_get_transfer(struct pipe_context *context,
return transfer;
}
static void *
i915_texture_transfer_map(struct pipe_context *pipe,
struct pipe_transfer *transfer)
......@@ -703,7 +752,7 @@ i915_texture_transfer_map(struct pipe_context *pipe,
if (resource->target != PIPE_TEXTURE_3D &&
resource->target != PIPE_TEXTURE_CUBE)
assert(box->z == 0);
offset = tex->image_offset[transfer->level][box->z];
offset = i915_texture_offset(tex, transfer->level, box->z);
map = iws->buffer_map(iws, tex->buffer,
(transfer->usage & PIPE_TRANSFER_WRITE) ? TRUE : FALSE);
......@@ -749,7 +798,6 @@ i915_texture_create(struct pipe_screen *screen,
struct i915_screen *is = i915_screen(screen);
struct i915_winsys *iws = is->iws;
struct i915_texture *tex = CALLOC_STRUCT(i915_texture);
size_t tex_size;
unsigned buf_usage = 0;
if (!tex)
......@@ -768,8 +816,6 @@ i915_texture_create(struct pipe_screen *screen,
goto fail;
}
tex_size = tex->stride * tex->total_nblocksy;
/* for scanouts and cursors, cursors arn't scanouts */
/* XXX: use a custom flag for cursors, don't rely on magically
......@@ -780,27 +826,15 @@ i915_texture_create(struct pipe_screen *screen,
else
buf_usage = I915_NEW_TEXTURE;
tex->buffer = iws->buffer_create(iws, tex_size, 64, buf_usage);
tex->buffer = iws->buffer_create_tiled(iws, &tex->stride, tex->total_nblocksy,
&tex->tiling, buf_usage);
if (!tex->buffer)
goto fail;
/* setup any hw fences */
if (tex->tiling) {
iws->buffer_set_fence_reg(iws, tex->buffer, tex->stride, tex->tiling);
}
#if 0
void *ptr = ws->buffer_map(ws, tex->buffer,
PIPE_BUFFER_USAGE_CPU_WRITE);
memset(ptr, 0x80, tex_size);
ws->buffer_unmap(ws, tex->buffer);
#endif
I915_DBG(DBG_TEXTURE, "%s: %p size %u, stride %u, blocks (%u, %u)\n", __func__,
tex, (unsigned int)tex_size, tex->stride,
I915_DBG(DBG_TEXTURE, "%s: %p stride %u, blocks (%u, %u) tiling %s\n", __func__,
tex, tex->stride,
tex->stride / util_format_get_blocksize(tex->b.b.format),
tex->total_nblocksy);
tex->total_nblocksy, get_tiling_string(tex->tiling));
return &tex->b.b;
......@@ -819,10 +853,11 @@ i915_texture_from_handle(struct pipe_screen * screen,
struct i915_winsys *iws = is->iws;
struct i915_winsys_buffer *buffer;
unsigned stride;
enum i915_winsys_buffer_tile tiling;
assert(screen);
buffer = iws->buffer_from_handle(iws, whandle, &stride);
buffer = iws->buffer_from_handle(iws, whandle, &tiling, &stride);
/* Only supports one type */
if ((template->target != PIPE_TEXTURE_2D &&
......@@ -842,6 +877,7 @@ i915_texture_from_handle(struct pipe_screen * screen,
tex->b.b.screen = screen;
tex->stride = stride;
tex->tiling = tiling;
tex->total_nblocksy = align_nblocksy(tex->b.b.format, tex->b.b.height0, 8);
i915_texture_set_level_info(tex, 0, 1);
......@@ -849,10 +885,10 @@ i915_texture_from_handle(struct pipe_screen * screen,
tex->buffer = buffer;
I915_DBG(DBG_TEXTURE, "%s: %p stride %u, blocks (%ux%u)\n", __func__,
I915_DBG(DBG_TEXTURE, "%s: %p stride %u, blocks (%u, %u) tiling %s\n", __func__,
tex, tex->stride,
tex->stride / util_format_get_blocksize(tex->b.b.format),
tex->total_nblocksy);
tex->total_nblocksy, get_tiling_string(tex->tiling));
return &tex->b.b;
}
......
......@@ -86,6 +86,22 @@ framebuffer_size(const struct pipe_framebuffer_state *fb,
}
}
static inline uint32_t
buf_3d_tiling_bits(enum i915_winsys_buffer_tile tiling)
{
uint32_t tiling_bits = 0;
switch (tiling) {
case I915_TILE_Y:
tiling_bits |= BUF_3D_TILE_WALK_Y;
case I915_TILE_X:
tiling_bits |= BUF_3D_TILED_SURFACE;
case I915_TILE_NONE:
break;
}
return tiling_bits;
}
/* Push the state into the sarea and/or texture memory.
*/
......@@ -220,44 +236,39 @@ i915_emit_hardware_state(struct i915_context *i915 )
struct pipe_surface *depth_surface = i915->framebuffer.zsbuf;
if (cbuf_surface) {
unsigned ctile = BUF_3D_USE_FENCE;
struct i915_texture *tex = i915_texture(cbuf_surface->texture);
unsigned offset;
assert(tex);
offset = tex->image_offset[cbuf_surface->u.tex.level][cbuf_surface->u.tex.first_layer];
OUT_BATCH(_3DSTATE_BUF_INFO_CMD);
OUT_BATCH(BUF_3D_ID_COLOR_BACK |
BUF_3D_PITCH(tex->stride) | /* pitch in bytes */
ctile);
buf_3d_tiling_bits(tex->tiling));
OUT_RELOC(tex->buffer,
I915_USAGE_RENDER,
offset);
0);
}
/* What happens if no zbuf??
*/
if (depth_surface) {
unsigned ztile = BUF_3D_USE_FENCE;
struct i915_texture *tex = i915_texture(depth_surface->texture);
unsigned offset;
unsigned offset = i915_texture_offset(tex, depth_surface->u.tex.level,
depth_surface->u.tex.first_layer);
assert(tex);
offset = tex->image_offset[depth_surface->u.tex.level][depth_surface->u.tex.first_layer];
assert(offset == 0);
OUT_BATCH(_3DSTATE_BUF_INFO_CMD);
assert(tex);
OUT_BATCH(BUF_3D_ID_DEPTH |
BUF_3D_PITCH(tex->stride) | /* pitch in bytes */
ztile);
buf_3d_tiling_bits(tex->tiling));
OUT_RELOC(tex->buffer,
I915_USAGE_RENDER,
offset);
0);
}
{
......@@ -299,12 +310,11 @@ i915_emit_hardware_state(struct i915_context *i915 )
if (enabled & (1 << unit)) {
struct i915_texture *texture = i915_texture(i915->fragment_sampler_views[unit]->texture);
struct i915_winsys_buffer *buf = texture->buffer;
uint offset = 0;
assert(buf);
count++;
OUT_RELOC(buf, I915_USAGE_SAMPLER, offset);
OUT_RELOC(buf, I915_USAGE_SAMPLER, 0);
OUT_BATCH(i915->current.texbuffer[unit][0]); /* MS3 */
OUT_BATCH(i915->current.texbuffer[unit][1]); /* MS4 */
}
......@@ -397,18 +407,33 @@ i915_emit_hardware_state(struct i915_context *i915 )
#if 01
/* drawing surface size */
/* 6 dwords, 0 relocs */
if (i915->hardware_dirty & I915_HW_STATIC)
{
uint w, h;
boolean k = framebuffer_size(&i915->framebuffer, &w, &h);
(void)k;
assert(k);
struct pipe_surface *cbuf_surface = i915->framebuffer.cbufs[0];
struct i915_texture *tex = i915_texture(cbuf_surface->texture);
unsigned x, y;
int layer;
uint32_t draw_offset;
boolean ret;
ret = framebuffer_size(&i915->framebuffer, &w, &h);
assert(ret);
layer = cbuf_surface->u.tex.first_layer;
x = tex->image_offset[cbuf_surface->u.tex.level][layer].nblocksx;
y = tex->image_offset[cbuf_surface->u.tex.level][layer].nblocksy;
draw_offset = x | (y << 16);
/* XXX flush only required when the draw_offset changes! */
OUT_BATCH(MI_FLUSH | INHIBIT_FLUSH_RENDER_CACHE);
OUT_BATCH(_3DSTATE_DRAW_RECT_CMD);
OUT_BATCH(0);
OUT_BATCH(0);
OUT_BATCH(((w - 1) & 0xffff) | ((h - 1) << 16));
OUT_BATCH(0);
OUT_BATCH(0);
OUT_BATCH(DRAW_RECT_DIS_DEPTH_OFS);
OUT_BATCH(draw_offset);
OUT_BATCH((w - 1 + x) | ((h - 1 + y) << 16));
OUT_BATCH(draw_offset);
}
#endif
......
......@@ -243,6 +243,23 @@ static uint translate_texture_format(enum pipe_format pipeFormat)
}
}
static inline uint32_t