diff options
| author | Younes Manton <younes.m@gmail.com> | 2008-12-01 23:48:29 -0500 | 
|---|---|---|
| committer | Younes Manton <younes.m@gmail.com> | 2008-12-02 16:15:12 -0500 | 
| commit | 6b4776df35c46892d7701072b8c03cb1cf2d6f01 (patch) | |
| tree | 019c35f691c5c1002ffd67f6f8e15bfec26665f3 /src | |
| parent | a6b7c0bcbebb7532b6728500a868b7c985e3f822 (diff) | |
nouveau: Use swizzled textures & render targets on nv40 when possible.
Diffstat (limited to 'src')
| -rw-r--r-- | src/gallium/drivers/nv40/nv40_fragtex.c | 3 | ||||
| -rw-r--r-- | src/gallium/drivers/nv40/nv40_miptree.c | 33 | ||||
| -rw-r--r-- | src/gallium/drivers/nv40/nv40_screen.c | 63 | ||||
| -rw-r--r-- | src/gallium/drivers/nv40/nv40_state.h | 3 | ||||
| -rw-r--r-- | src/gallium/drivers/nv40/nv40_state_fb.c | 38 | ||||
| -rw-r--r-- | src/gallium/winsys/drm/nouveau/nv04_surface.c | 3 | 
6 files changed, 131 insertions, 12 deletions
diff --git a/src/gallium/drivers/nv40/nv40_fragtex.c b/src/gallium/drivers/nv40/nv40_fragtex.c index 566d5a8d5b..0227d22620 100644 --- a/src/gallium/drivers/nv40/nv40_fragtex.c +++ b/src/gallium/drivers/nv40/nv40_fragtex.c @@ -66,7 +66,6 @@ nv40_fragtex_build(struct nv40_context *nv40, int unit)  	struct nv40_texture_format *tf;  	struct nouveau_stateobj *so;  	uint32_t txf, txs, txp; -	int swizzled = 0; /*XXX: implement in region code? */  	unsigned tex_flags = NOUVEAU_BO_VRAM | NOUVEAU_BO_GART | NOUVEAU_BO_RD;  	tf = nv40_fragtex_format(pt->format); @@ -98,7 +97,7 @@ nv40_fragtex_build(struct nv40_context *nv40, int unit)  		return NULL;  	} -	if (swizzled) { +	if (!(pt->tex_usage & NOUVEAU_TEXTURE_USAGE_LINEAR)) {  		txp = 0;  	} else {  		txp  = nv40mt->level[0].pitch; diff --git a/src/gallium/drivers/nv40/nv40_miptree.c b/src/gallium/drivers/nv40/nv40_miptree.c index f321b72149..6516bff4b8 100644 --- a/src/gallium/drivers/nv40/nv40_miptree.c +++ b/src/gallium/drivers/nv40/nv40_miptree.c @@ -65,9 +65,32 @@ nv40_miptree_create(struct pipe_screen *pscreen, const struct pipe_texture *pt)  	mt->base = *pt;  	mt->base.refcount = 1;  	mt->base.screen = pscreen; +	mt->shadow_tex = NULL; +	mt->shadow_surface = NULL;  	nv40_miptree_layout(mt); +	/* Swizzled textures must be POT */ +	if (pt->width[0] & (pt->width[0] - 1) || +	    pt->height[0] & (pt->height[0] - 1)) +		mt->base.tex_usage |= NOUVEAU_TEXTURE_USAGE_LINEAR; +	else +	if (pt->tex_usage & (PIPE_TEXTURE_USAGE_PRIMARY | +	                     PIPE_TEXTURE_USAGE_DISPLAY_TARGET)) +		mt->base.tex_usage |= NOUVEAU_TEXTURE_USAGE_LINEAR; +	else { +		switch (pt->format) { +		/* TODO: Figure out which formats can be swizzled */ +		case PIPE_FORMAT_A8R8G8B8_UNORM: +		case PIPE_FORMAT_X8R8G8B8_UNORM: +		/* XXX: Re-enable when SIFM size limits are fixed */ +		/*case PIPE_FORMAT_R16_SNORM:*/ +			break; +		default: +			mt->base.tex_usage |= NOUVEAU_TEXTURE_USAGE_LINEAR; +		} +	} +  	mt->buffer = ws->buffer_create(ws, 256,  				       PIPE_BUFFER_USAGE_PIXEL |  				       NOUVEAU_BUFFER_USAGE_TEXTURE, @@ -91,13 +114,18 @@ nv40_miptree_release(struct pipe_screen *pscreen, struct pipe_texture **ppt)  	if (--pt->refcount)  		return; -  	pipe_buffer_reference(pscreen, &mt->buffer, NULL);  	for (l = 0; l <= pt->last_level; l++) {  		if (mt->level[l].image_offset)  			FREE(mt->level[l].image_offset);  	} +	if (mt->shadow_tex) { +		assert(mt->shadow_surface); +		pscreen->tex_surface_release(pscreen, &mt->shadow_surface); +		nv40_miptree_release(pscreen, &mt->shadow_tex); +	} +  	FREE(mt);  } @@ -125,6 +153,9 @@ nv40_miptree_surface_new(struct pipe_screen *pscreen, struct pipe_texture *pt,  	ps->status = PIPE_SURFACE_STATUS_DEFINED;  	ps->refcount = 1;  	ps->winsys = pscreen->winsys; +	ps->face = face; +	ps->level = level; +	ps->zslice = zslice;  	if (pt->target == PIPE_TEXTURE_CUBE) {  		ps->offset = mt->level[level].image_offset[face]; diff --git a/src/gallium/drivers/nv40/nv40_screen.c b/src/gallium/drivers/nv40/nv40_screen.c index ada0238511..25c7868296 100644 --- a/src/gallium/drivers/nv40/nv40_screen.c +++ b/src/gallium/drivers/nv40/nv40_screen.c @@ -137,22 +137,73 @@ static void *  nv40_surface_map(struct pipe_screen *screen, struct pipe_surface *surface,  		 unsigned flags )  { -	struct pipe_winsys *ws = screen->winsys; -	void *map; +	struct pipe_winsys	*ws = screen->winsys; +	struct pipe_surface	*surface_to_map; +	void			*map; -	map = ws->buffer_map(ws, surface->buffer, flags); +	if (!(surface->texture->tex_usage & NOUVEAU_TEXTURE_USAGE_LINEAR)) { +		struct nv40_miptree *mt = (struct nv40_miptree *)surface->texture; + +		if (!mt->shadow_tex) { +			unsigned old_tex_usage = surface->texture->tex_usage; +			surface->texture->tex_usage = NOUVEAU_TEXTURE_USAGE_LINEAR; +			mt->shadow_tex = screen->texture_create(screen, surface->texture); +			surface->texture->tex_usage = old_tex_usage; + +			assert(mt->shadow_tex->tex_usage & NOUVEAU_TEXTURE_USAGE_LINEAR); +			mt->shadow_surface = screen->get_tex_surface +			( +				screen, mt->shadow_tex, +				surface->face, surface->level, surface->zslice, +				surface->usage +			); +		} + +		surface_to_map = mt->shadow_surface; +	} +	else +		surface_to_map = surface; + +	assert(surface_to_map); + +	map = ws->buffer_map(ws, surface_to_map->buffer, flags);  	if (!map)  		return NULL; -	return map + surface->offset; +	return map + surface_to_map->offset;  }  static void  nv40_surface_unmap(struct pipe_screen *screen, struct pipe_surface *surface)  { -	struct pipe_winsys *ws = screen->winsys; +	struct pipe_winsys	*ws = screen->winsys; +	struct pipe_surface	*surface_to_unmap; + +	/* TODO: Copy from shadow just before push buffer is flushed instead. +	         There are probably some programs that map/unmap excessively +	         before rendering. */ +	if (!(surface->texture->tex_usage & NOUVEAU_TEXTURE_USAGE_LINEAR)) { +		struct nv40_miptree *mt = (struct nv40_miptree *)surface->texture; -	ws->buffer_unmap(ws, surface->buffer); +		assert(mt->shadow_tex); + +		surface_to_unmap = mt->shadow_surface; +	} +	else +		surface_to_unmap = surface; + +	assert(surface_to_unmap); + +	ws->buffer_unmap(ws, surface_to_unmap->buffer); + +	if (surface_to_unmap != surface) { +		struct nv40_screen *nvscreen = nv40_screen(screen); + +		nvscreen->nvws->surface_copy(nvscreen->nvws, +		                             surface, 0, 0, +		                             surface_to_unmap, 0, 0, +		                             surface->width, surface->height); +	}  }  static void diff --git a/src/gallium/drivers/nv40/nv40_state.h b/src/gallium/drivers/nv40/nv40_state.h index 8a9d8c8fdf..9c55903ae3 100644 --- a/src/gallium/drivers/nv40/nv40_state.h +++ b/src/gallium/drivers/nv40/nv40_state.h @@ -79,6 +79,9 @@ struct nv40_miptree {  	struct pipe_buffer *buffer;  	uint total_size; +	struct pipe_texture *shadow_tex; +	struct pipe_surface *shadow_surface; +  	struct {  		uint pitch;  		uint *image_offset; diff --git a/src/gallium/drivers/nv40/nv40_state_fb.c b/src/gallium/drivers/nv40/nv40_state_fb.c index 0e4e60eaa7..f903b22ba0 100644 --- a/src/gallium/drivers/nv40/nv40_state_fb.c +++ b/src/gallium/drivers/nv40/nv40_state_fb.c @@ -1,5 +1,31 @@  #include "nv40_context.h" +static INLINE int log2i(int i) +{ +	int r = 0; + +	if (i & 0xffff0000) { +		i >>= 16; +		r += 16; +	} +	if (i & 0x0000ff00) { +		i >>= 8; +		r += 8; +	} +	if (i & 0x000000f0) { +		i >>= 4; +		r += 4; +	} +	if (i & 0x0000000c) { +		i >>= 2; +		r += 2; +	} +	if (i & 0x00000002) { +		r += 1; +	} +	return r; +} +  static boolean  nv40_state_framebuffer_validate(struct nv40_context *nv40)  { @@ -32,7 +58,17 @@ nv40_state_framebuffer_validate(struct nv40_context *nv40)  		zeta = fb->zsbuf;  	} -	rt_format = NV40TCL_RT_FORMAT_TYPE_LINEAR; +	if (!(rt[0]->texture->tex_usage & NOUVEAU_TEXTURE_USAGE_LINEAR)) { +		assert(!(fb->width & (fb->width - 1)) && !(fb->height & (fb->height - 1))); +		for (i = 1; i < fb->num_cbufs; i++) +			assert(!(rt[i]->texture->tex_usage & NOUVEAU_TEXTURE_USAGE_LINEAR)); + +		rt_format = NV40TCL_RT_FORMAT_TYPE_SWIZZLED | +		            log2i(fb->width) << NV40TCL_RT_FORMAT_LOG2_WIDTH_SHIFT | +		            log2i(fb->height) << NV40TCL_RT_FORMAT_LOG2_HEIGHT_SHIFT; +	} +	else +		rt_format = NV40TCL_RT_FORMAT_TYPE_LINEAR;  	switch (colour_format) {  	case PIPE_FORMAT_A8R8G8B8_UNORM: diff --git a/src/gallium/winsys/drm/nouveau/nv04_surface.c b/src/gallium/winsys/drm/nouveau/nv04_surface.c index 4f37af7927..1178620240 100644 --- a/src/gallium/winsys/drm/nouveau/nv04_surface.c +++ b/src/gallium/winsys/drm/nouveau/nv04_surface.c @@ -35,10 +35,9 @@ nv04_surface_format(enum pipe_format format)  	switch (format) {  	case PIPE_FORMAT_A8_UNORM:  		return NV04_CONTEXT_SURFACES_2D_FORMAT_Y8; +	case PIPE_FORMAT_R16_SNORM:  	case PIPE_FORMAT_R5G6B5_UNORM:  		return NV04_CONTEXT_SURFACES_2D_FORMAT_R5G6B5; -	case PIPE_FORMAT_R16_SNORM: -		return NV04_CONTEXT_SURFACES_2D_FORMAT_Y16;  	case PIPE_FORMAT_X8R8G8B8_UNORM:  	case PIPE_FORMAT_A8R8G8B8_UNORM:  		return NV04_CONTEXT_SURFACES_2D_FORMAT_A8R8G8B8;  | 
