mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-05-08 04:48:08 +02:00
softpipe: Simplify texture memory layout.
This commit is contained in:
parent
51ea675745
commit
ede7b00b59
3 changed files with 30 additions and 346 deletions
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue