softpipe: Simplify texture memory layout.

This commit is contained in:
Michel Dänzer 2008-01-10 10:03:47 +01:00
parent 51ea675745
commit ede7b00b59
3 changed files with 30 additions and 346 deletions

View file

@ -46,20 +46,6 @@ softpipe_get_tex_surface(struct pipe_context *pipe,
{
struct softpipe_texture *spt = softpipe_texture(pt);
struct pipe_surface *ps;
unsigned offset; /* in bytes */
offset = spt->level_offset[level];
if (pt->target == PIPE_TEXTURE_CUBE) {
offset += spt->image_offset[level][face] * pt->cpp;
}
else if (pt->target == PIPE_TEXTURE_3D) {
offset += spt->image_offset[level][zslice] * pt->cpp;
}
else {
assert(face == 0);
assert(zslice == 0);
}
ps = pipe->winsys->surface_alloc(pipe->winsys);
if (ps) {
@ -69,8 +55,17 @@ softpipe_get_tex_surface(struct pipe_context *pipe,
ps->cpp = pt->cpp;
ps->width = pt->width[level];
ps->height = pt->height[level];
ps->pitch = spt->pitch;
ps->offset = offset;
ps->pitch = ps->width;
ps->offset = spt->level_offset[level];
if (pt->target == PIPE_TEXTURE_CUBE || pt->target == PIPE_TEXTURE_3D) {
ps->offset += ((pt->target == PIPE_TEXTURE_CUBE) ? face : zslice) *
(pt->compressed ? ps->height/4 : ps->height) *
ps->width * ps->cpp;
} else {
assert(face == 0);
assert(zslice == 0);
}
}
return ps;
}

View file

@ -41,10 +41,7 @@
#include "sp_texture.h"
/* At the moment, just make softpipe use the same layout for its
* textures as the i945. Softpipe needs some sort of texture layout,
* this one was handy. May be worthwhile to simplify this code a
* little.
/* Simple, maximally packed layout.
*/
static unsigned minify( unsigned d )
@ -53,319 +50,35 @@ static unsigned minify( unsigned d )
}
static void
sp_miptree_set_level_info(struct softpipe_texture *spt,
unsigned level,
unsigned nr_images,
unsigned x, unsigned y, unsigned w, unsigned h,
unsigned d)
softpipe_texture_layout(struct softpipe_texture * spt)
{
struct pipe_texture *pt = &spt->base;
assert(level < PIPE_MAX_TEXTURE_LEVELS);
pt->width[level] = w;
pt->height[level] = h;
pt->depth[level] = d;
spt->nr_images[level] = nr_images;
spt->level_offset[level] = (x + y * spt->pitch) * pt->cpp;
/*
DBG("%s level %d size: %d,%d,%d offset %d,%d (0x%x)\n", __FUNCTION__,
level, w, h, d, x, y, spt->level_offset[level]);
*/
/* Not sure when this would happen, but anyway:
*/
if (spt->image_offset[level]) {
FREE( spt->image_offset[level] );
spt->image_offset[level] = NULL;
}
assert(nr_images);
assert(!spt->image_offset[level]);
spt->image_offset[level] = (unsigned *) MALLOC( nr_images * sizeof(unsigned) );
spt->image_offset[level][0] = 0;
}
static void
sp_miptree_set_image_offset(struct softpipe_texture *spt,
unsigned level, unsigned img, unsigned x, unsigned y)
{
if (img == 0 && level == 0)
assert(x == 0 && y == 0);
assert(img < spt->nr_images[level]);
spt->image_offset[level][img] = (x + y * spt->pitch);
/*
DBG("%s level %d img %d pos %d,%d image_offset %x\n",
__FUNCTION__, level, img, x, y, spt->image_offset[level][img]);
*/
}
static void
sp_miptree_layout_2d( struct softpipe_texture *spt )
{
struct pipe_texture *pt = &spt->base;
int align_h = 2, align_w = 4;
unsigned level;
unsigned x = 0;
unsigned y = 0;
unsigned width = pt->width[0];
unsigned height = pt->height[0];
unsigned depth = pt->depth[0];
spt->pitch = pt->width[0];
/* XXX FIX THIS:
* we use alignment=64 bytes in sp_region_alloc(). If we change
* that, change this too.
*/
if (spt->pitch < 16)
spt->pitch = 16;
/* May need to adjust pitch to accomodate the placement of
* the 2nd mipmap. This occurs when the alignment
* constraints of mipmap placement push the right edge of the
* 2nd mipmap out past the width of its parent.
*/
if (pt->first_level != pt->last_level) {
unsigned mip1_width = align(minify(pt->width[0]), align_w)
+ minify(minify(pt->width[0]));
if (mip1_width > pt->width[0])
spt->pitch = mip1_width;
}
/* Pitch must be a whole number of dwords, even though we
* express it in texels.
*/
spt->pitch = align(spt->pitch * pt->cpp, 4) / pt->cpp;
spt->total_height = 0;
spt->buffer_size = 0;
for ( level = pt->first_level ; level <= pt->last_level ; level++ ) {
unsigned img_height;
pt->width[level] = width;
pt->height[level] = height;
pt->depth[level] = depth;
sp_miptree_set_level_info(spt, level, 1, x, y, width, height, 1);
spt->level_offset[level] = spt->buffer_size;
if (pt->compressed)
img_height = MAX2(1, height/4);
else
img_height = align(height, align_h);
/* Because the images are packed better, the final offset
* might not be the maximal one:
*/
spt->total_height = MAX2(spt->total_height, y + img_height);
/* Layout_below: step right after second mipmap.
*/
if (level == pt->first_level + 1) {
x += align(width, align_w);
}
else {
y += img_height;
}
spt->buffer_size += ((pt->compressed) ? MAX2(1, height/4) : height) *
((pt->target == PIPE_TEXTURE_CUBE) ? 6 : depth) *
width * pt->cpp;
width = minify(width);
height = minify(height);
depth = minify(depth);
}
}
static const int initial_offsets[6][2] = {
{0, 0},
{0, 2},
{1, 0},
{1, 2},
{1, 1},
{1, 3}
};
static const int step_offsets[6][2] = {
{0, 2},
{0, 2},
{-1, 2},
{-1, 2},
{-1, 1},
{-1, 1}
};
static boolean
softpipe_mipmap_tree_layout(struct pipe_context *pipe, struct softpipe_texture * spt)
{
struct pipe_texture *pt = &spt->base;
unsigned level;
switch (pt->target) {
case PIPE_TEXTURE_CUBE:{
const unsigned dim = pt->width[0];
unsigned face;
unsigned lvlWidth = pt->width[0], lvlHeight = pt->height[0];
assert(lvlWidth == lvlHeight); /* cubemap images are square */
/* Depending on the size of the largest images, pitch can be
* determined either by the old-style packing of cubemap faces,
* or the final row of 4x4, 2x2 and 1x1 faces below this.
*/
if (dim > 32)
spt->pitch = ((dim * pt->cpp * 2 + 3) & ~3) / pt->cpp;
else
spt->pitch = 14 * 8;
spt->total_height = dim * 4 + 4;
/* Set all the levels to effectively occupy the whole rectangular region.
*/
for (level = pt->first_level; level <= pt->last_level; level++) {
sp_miptree_set_level_info(spt, level, 6,
0, 0,
lvlWidth, lvlHeight, 1);
lvlWidth /= 2;
lvlHeight /= 2;
}
for (face = 0; face < 6; face++) {
unsigned x = initial_offsets[face][0] * dim;
unsigned y = initial_offsets[face][1] * dim;
unsigned d = dim;
if (dim == 4 && face >= 4) {
y = spt->total_height - 4;
x = (face - 4) * 8;
}
else if (dim < 4 && (face > 0 || pt->first_level > 0)) {
y = spt->total_height - 4;
x = face * 8;
}
for (level = pt->first_level; level <= pt->last_level; level++) {
sp_miptree_set_image_offset(spt, level, face, x, y);
d >>= 1;
switch (d) {
case 4:
switch (face) {
case PIPE_TEX_FACE_POS_X:
case PIPE_TEX_FACE_NEG_X:
x += step_offsets[face][0] * d;
y += step_offsets[face][1] * d;
break;
case PIPE_TEX_FACE_POS_Y:
case PIPE_TEX_FACE_NEG_Y:
y += 12;
x -= 8;
break;
case PIPE_TEX_FACE_POS_Z:
case PIPE_TEX_FACE_NEG_Z:
y = spt->total_height - 4;
x = (face - 4) * 8;
break;
}
case 2:
y = spt->total_height - 4;
x = 16 + face * 8;
break;
case 1:
x += 48;
break;
default:
x += step_offsets[face][0] * d;
y += step_offsets[face][1] * d;
break;
}
}
}
break;
}
case PIPE_TEXTURE_3D:{
unsigned width = pt->width[0];
unsigned height = pt->height[0];
unsigned depth = pt->depth[0];
unsigned pack_x_pitch, pack_x_nr;
unsigned pack_y_pitch;
unsigned level;
spt->pitch = ((pt->width[0] * pt->cpp + 3) & ~3) / pt->cpp;
spt->total_height = 0;
pack_y_pitch = MAX2(pt->height[0], 2);
pack_x_pitch = spt->pitch;
pack_x_nr = 1;
for (level = pt->first_level; level <= pt->last_level; level++) {
unsigned nr_images = pt->target == PIPE_TEXTURE_3D ? depth : 6;
int x = 0;
int y = 0;
unsigned q, j;
sp_miptree_set_level_info(spt, level, nr_images,
0, spt->total_height,
width, height, depth);
for (q = 0; q < nr_images;) {
for (j = 0; j < pack_x_nr && q < nr_images; j++, q++) {
sp_miptree_set_image_offset(spt, level, q, x, y);
x += pack_x_pitch;
}
x = 0;
y += pack_y_pitch;
}
spt->total_height += y;
if (pack_x_pitch > 4) {
pack_x_pitch >>= 1;
pack_x_nr <<= 1;
assert(pack_x_pitch * pack_x_nr <= spt->pitch);
}
if (pack_y_pitch > 2) {
pack_y_pitch >>= 1;
}
width = minify(width);
height = minify(height);
depth = minify(depth);
}
break;
}
case PIPE_TEXTURE_1D:
case PIPE_TEXTURE_2D:
// case PIPE_TEXTURE_RECTANGLE:
sp_miptree_layout_2d(spt);
break;
default:
assert(0);
break;
}
/*
DBG("%s: %dx%dx%d - sz 0x%x\n", __FUNCTION__,
spt->pitch,
spt->total_height, pt->cpp, spt->pitch * spt->total_height * pt->cpp);
*/
return TRUE;
}
void
softpipe_texture_create(struct pipe_context *pipe, struct pipe_texture **pt)
{
@ -376,15 +89,13 @@ softpipe_texture_create(struct pipe_context *pipe, struct pipe_texture **pt)
memset(&spt->base + 1, 0,
sizeof(struct softpipe_texture) - sizeof(struct pipe_texture));
if (softpipe_mipmap_tree_layout(pipe, spt)) {
spt->buffer = pipe->winsys->buffer_create(pipe->winsys, 32, 0, 0);
softpipe_texture_layout(spt);
if (spt->buffer) {
pipe->winsys->buffer_data(pipe->winsys, spt->buffer,
spt->pitch * spt->base.cpp *
spt->total_height, NULL,
PIPE_BUFFER_USAGE_PIXEL);
}
spt->buffer = pipe->winsys->buffer_create(pipe->winsys, 32, 0, 0);
if (spt->buffer) {
pipe->winsys->buffer_data(pipe->winsys, spt->buffer, spt->buffer_size,
NULL, PIPE_BUFFER_USAGE_PIXEL);
}
if (!spt->buffer) {
@ -408,7 +119,6 @@ softpipe_texture_release(struct pipe_context *pipe, struct pipe_texture **pt)
*/
if (--(*pt)->refcount <= 0) {
struct softpipe_texture *spt = softpipe_texture(*pt);
uint i;
/*
DBG("%s deleting %p\n", __FUNCTION__, (void *) spt);
@ -416,10 +126,6 @@ softpipe_texture_release(struct pipe_context *pipe, struct pipe_texture **pt)
pipe->winsys->buffer_reference(pipe->winsys, &spt->buffer, NULL);
for (i = 0; i < PIPE_MAX_TEXTURE_LEVELS; i++)
if (spt->image_offset[i])
free(spt->image_offset[i]);
free(spt);
}
*pt = NULL;

View file

@ -10,29 +10,12 @@ struct softpipe_texture
{
struct pipe_texture base;
/* Derived from the above:
*/
unsigned pitch;
unsigned depth_pitch; /* per-image on i945? */
unsigned total_height;
unsigned nr_images[PIPE_MAX_TEXTURE_LEVELS];
/* Explicitly store the offset of each image for each cube face or
* depth value. Pretty much have to accept that hardware formats
* are going to be so diverse that there is no unified way to
* compute the offsets of depth/cube images within a mipmap level,
* so have to store them as a lookup table:
*/
unsigned *image_offset[PIPE_MAX_TEXTURE_LEVELS]; /**< array [depth] of offsets */
/* Includes image offset tables:
*/
unsigned long level_offset[PIPE_MAX_TEXTURE_LEVELS];
/* The data is held here:
*/
struct pipe_buffer_handle *buffer;
unsigned long buffer_size;
};