953 lines
25 KiB
C
953 lines
25 KiB
C
/**************************************************************************
|
|
*
|
|
* Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas.
|
|
* All Rights Reserved.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the
|
|
* "Software"), to deal in the Software without restriction, including
|
|
* without limitation the rights to use, copy, modify, merge, publish,
|
|
* distribute, sub license, and/or sell copies of the Software, and to
|
|
* permit persons to whom the Software is furnished to do so, subject to
|
|
* the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice (including the
|
|
* next paragraph) shall be included in all copies or substantial portions
|
|
* of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
|
|
* IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
|
|
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
*
|
|
**************************************************************************/
|
|
/*
|
|
* Authors:
|
|
* Keith Whitwell <keith@tungstengraphics.com>
|
|
* Michel Dänzer <michel@tungstengraphics.com>
|
|
*/
|
|
|
|
#include "pipe/p_state.h"
|
|
#include "pipe/p_context.h"
|
|
#include "pipe/p_defines.h"
|
|
#include "pipe/p_inlines.h"
|
|
#include "pipe/internal/p_winsys_screen.h"
|
|
#include "util/u_math.h"
|
|
#include "util/u_memory.h"
|
|
|
|
#include "i915_context.h"
|
|
#include "i915_texture.h"
|
|
#include "i915_debug.h"
|
|
#include "i915_screen.h"
|
|
#include "intel_winsys.h"
|
|
|
|
|
|
/*
|
|
* Helper function and arrays
|
|
*/
|
|
|
|
|
|
/**
|
|
* Initial offset for Cube map.
|
|
*/
|
|
static const int initial_offsets[6][2] = {
|
|
{0, 0},
|
|
{0, 2},
|
|
{1, 0},
|
|
{1, 2},
|
|
{1, 1},
|
|
{1, 3}
|
|
};
|
|
|
|
/**
|
|
* Step offsets for Cube map.
|
|
*/
|
|
static const int step_offsets[6][2] = {
|
|
{0, 2},
|
|
{0, 2},
|
|
{-1, 2},
|
|
{-1, 2},
|
|
{-1, 1},
|
|
{-1, 1}
|
|
};
|
|
|
|
static unsigned
|
|
power_of_two(unsigned x)
|
|
{
|
|
unsigned value = 1;
|
|
while (value < x)
|
|
value = value << 1;
|
|
return value;
|
|
}
|
|
|
|
static unsigned
|
|
round_up(unsigned n, unsigned multiple)
|
|
{
|
|
return (n + multiple - 1) & ~(multiple - 1);
|
|
}
|
|
|
|
|
|
/*
|
|
* More advanced helper funcs
|
|
*/
|
|
|
|
|
|
static void
|
|
i915_miptree_set_level_info(struct i915_texture *tex,
|
|
unsigned level,
|
|
unsigned nr_images,
|
|
unsigned w, unsigned h, unsigned d)
|
|
{
|
|
struct pipe_texture *pt = &tex->base;
|
|
|
|
assert(level < PIPE_MAX_TEXTURE_LEVELS);
|
|
|
|
pt->nblocksx[level] = pf_get_nblocksx(&pt->block, w);
|
|
pt->nblocksy[level] = pf_get_nblocksy(&pt->block, h);
|
|
|
|
tex->nr_images[level] = nr_images;
|
|
|
|
/*
|
|
DBG("%s level %d size: %d,%d,%d offset %d,%d (0x%x)\n", __FUNCTION__,
|
|
level, w, h, d, x, y, tex->level_offset[level]);
|
|
*/
|
|
|
|
/* Not sure when this would happen, but anyway:
|
|
*/
|
|
if (tex->image_offset[level]) {
|
|
FREE(tex->image_offset[level]);
|
|
tex->image_offset[level] = NULL;
|
|
}
|
|
|
|
assert(nr_images);
|
|
assert(!tex->image_offset[level]);
|
|
|
|
tex->image_offset[level] = (unsigned *) MALLOC(nr_images * sizeof(unsigned));
|
|
tex->image_offset[level][0] = 0;
|
|
}
|
|
|
|
static void
|
|
i915_miptree_set_image_offset(struct i915_texture *tex,
|
|
unsigned level, unsigned img, unsigned x, unsigned y)
|
|
{
|
|
if (img == 0 && level == 0)
|
|
assert(x == 0 && y == 0);
|
|
|
|
assert(img < tex->nr_images[level]);
|
|
|
|
tex->image_offset[level][img] = y * tex->stride + x * tex->base.block.size;
|
|
|
|
/*
|
|
printf("%s level %d img %d pos %d,%d image_offset %x\n",
|
|
__FUNCTION__, level, img, x, y, tex->image_offset[level][img]);
|
|
*/
|
|
}
|
|
|
|
|
|
/*
|
|
* i915 layout functions, some used by i945
|
|
*/
|
|
|
|
|
|
/**
|
|
* Special case to deal with scanout textures.
|
|
*/
|
|
static boolean
|
|
i915_scanout_layout(struct i915_texture *tex)
|
|
{
|
|
struct pipe_texture *pt = &tex->base;
|
|
|
|
if (pt->last_level > 0 || pt->block.size != 4)
|
|
return FALSE;
|
|
|
|
i915_miptree_set_level_info(tex, 0, 1,
|
|
tex->base.width0,
|
|
tex->base.height0,
|
|
1);
|
|
i915_miptree_set_image_offset(tex, 0, 0, 0, 0);
|
|
|
|
if (tex->base.width0 >= 240) {
|
|
tex->stride = power_of_two(tex->base.nblocksx[0] * pt->block.size);
|
|
tex->total_nblocksy = round_up(tex->base.nblocksy[0], 8);
|
|
tex->hw_tiled = INTEL_TILE_X;
|
|
} else if (tex->base.width0 == 64 && tex->base.height0 == 64) {
|
|
tex->stride = power_of_two(tex->base.nblocksx[0] * pt->block.size);
|
|
tex->total_nblocksy = round_up(tex->base.nblocksy[0], 8);
|
|
} else {
|
|
return FALSE;
|
|
}
|
|
|
|
debug_printf("%s size: %d,%d,%d offset %d,%d (0x%x)\n", __FUNCTION__,
|
|
tex->base.width0, tex->base.height0, pt->block.size,
|
|
tex->stride, tex->total_nblocksy, tex->stride * tex->total_nblocksy);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* Special case to deal with shared textures.
|
|
*/
|
|
static boolean
|
|
i915_display_target_layout(struct i915_texture *tex)
|
|
{
|
|
struct pipe_texture *pt = &tex->base;
|
|
|
|
if (pt->last_level > 0 || pt->block.size != 4)
|
|
return FALSE;
|
|
|
|
/* fallback to normal textures for small textures */
|
|
if (tex->base.width0 < 240)
|
|
return FALSE;
|
|
|
|
i915_miptree_set_level_info(tex, 0, 1,
|
|
tex->base.width0,
|
|
tex->base.height0,
|
|
1);
|
|
i915_miptree_set_image_offset(tex, 0, 0, 0, 0);
|
|
|
|
tex->stride = power_of_two(tex->base.nblocksx[0] * pt->block.size);
|
|
tex->total_nblocksy = round_up(tex->base.nblocksy[0], 8);
|
|
tex->hw_tiled = INTEL_TILE_X;
|
|
|
|
debug_printf("%s size: %d,%d,%d offset %d,%d (0x%x)\n", __FUNCTION__,
|
|
tex->base.width0, tex->base.height0, pt->block.size,
|
|
tex->stride, tex->total_nblocksy, tex->stride * tex->total_nblocksy);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
i915_miptree_layout_2d(struct i915_texture *tex)
|
|
{
|
|
struct pipe_texture *pt = &tex->base;
|
|
unsigned level;
|
|
unsigned width = pt->width0;
|
|
unsigned height = pt->height0;
|
|
unsigned nblocksx = pt->nblocksx[0];
|
|
unsigned nblocksy = pt->nblocksy[0];
|
|
|
|
/* used for scanouts that need special layouts */
|
|
if (tex->base.tex_usage & PIPE_TEXTURE_USAGE_PRIMARY)
|
|
if (i915_scanout_layout(tex))
|
|
return;
|
|
|
|
/* for shared buffers we use some very like scanout */
|
|
if (tex->base.tex_usage & PIPE_TEXTURE_USAGE_DISPLAY_TARGET)
|
|
if (i915_display_target_layout(tex))
|
|
return;
|
|
|
|
tex->stride = round_up(pt->nblocksx[0] * pt->block.size, 4);
|
|
tex->total_nblocksy = 0;
|
|
|
|
for (level = 0; level <= pt->last_level; level++) {
|
|
i915_miptree_set_level_info(tex, level, 1, width, height, 1);
|
|
i915_miptree_set_image_offset(tex, level, 0, 0, tex->total_nblocksy);
|
|
|
|
nblocksy = round_up(MAX2(2, nblocksy), 2);
|
|
|
|
tex->total_nblocksy += nblocksy;
|
|
|
|
width = u_minify(width, 1);
|
|
height = u_minify(height, 1);
|
|
nblocksx = pf_get_nblocksx(&pt->block, width);
|
|
nblocksy = pf_get_nblocksy(&pt->block, height);
|
|
}
|
|
}
|
|
|
|
static void
|
|
i915_miptree_layout_3d(struct i915_texture *tex)
|
|
{
|
|
struct pipe_texture *pt = &tex->base;
|
|
unsigned level;
|
|
|
|
unsigned width = pt->width0;
|
|
unsigned height = pt->height0;
|
|
unsigned depth = pt->depth0;
|
|
unsigned nblocksx = pt->nblocksx[0];
|
|
unsigned nblocksy = pt->nblocksy[0];
|
|
unsigned stack_nblocksy = 0;
|
|
|
|
/* Calculate the size of a single slice.
|
|
*/
|
|
tex->stride = round_up(pt->nblocksx[0] * pt->block.size, 4);
|
|
|
|
/* XXX: hardware expects/requires 9 levels at minimum.
|
|
*/
|
|
for (level = 0; level <= MAX2(8, pt->last_level); level++) {
|
|
i915_miptree_set_level_info(tex, level, depth, width, height, depth);
|
|
|
|
stack_nblocksy += MAX2(2, nblocksy);
|
|
|
|
width = u_minify(width, 1);
|
|
height = u_minify(height, 1);
|
|
nblocksx = pf_get_nblocksx(&pt->block, width);
|
|
nblocksy = pf_get_nblocksy(&pt->block, height);
|
|
}
|
|
|
|
/* Fixup depth image_offsets:
|
|
*/
|
|
for (level = 0; level <= pt->last_level; level++) {
|
|
unsigned i;
|
|
for (i = 0; i < depth; i++)
|
|
i915_miptree_set_image_offset(tex, level, i, 0, i * stack_nblocksy);
|
|
|
|
depth = u_minify(depth, 1);
|
|
}
|
|
|
|
/* Multiply slice size by texture depth for total size. It's
|
|
* remarkable how wasteful of memory the i915 texture layouts
|
|
* are. They are largely fixed in the i945.
|
|
*/
|
|
tex->total_nblocksy = stack_nblocksy * pt->depth0;
|
|
}
|
|
|
|
static void
|
|
i915_miptree_layout_cube(struct i915_texture *tex)
|
|
{
|
|
struct pipe_texture *pt = &tex->base;
|
|
unsigned width = pt->width0, height = pt->height0;
|
|
const unsigned nblocks = pt->nblocksx[0];
|
|
unsigned level;
|
|
unsigned face;
|
|
|
|
assert(width == height); /* cubemap images are square */
|
|
|
|
/* double pitch for cube layouts */
|
|
tex->stride = round_up(nblocks * pt->block.size * 2, 4);
|
|
tex->total_nblocksy = nblocks * 4;
|
|
|
|
for (level = 0; level <= pt->last_level; level++) {
|
|
i915_miptree_set_level_info(tex, level, 6, width, height, 1);
|
|
width /= 2;
|
|
height /= 2;
|
|
}
|
|
|
|
for (face = 0; face < 6; face++) {
|
|
unsigned x = initial_offsets[face][0] * nblocks;
|
|
unsigned y = initial_offsets[face][1] * nblocks;
|
|
unsigned d = nblocks;
|
|
|
|
for (level = 0; level <= pt->last_level; level++) {
|
|
i915_miptree_set_image_offset(tex, level, face, x, y);
|
|
d >>= 1;
|
|
x += step_offsets[face][0] * d;
|
|
y += step_offsets[face][1] * d;
|
|
}
|
|
}
|
|
}
|
|
|
|
static boolean
|
|
i915_miptree_layout(struct i915_texture * tex)
|
|
{
|
|
struct pipe_texture *pt = &tex->base;
|
|
|
|
switch (pt->target) {
|
|
case PIPE_TEXTURE_1D:
|
|
case PIPE_TEXTURE_2D:
|
|
i915_miptree_layout_2d(tex);
|
|
break;
|
|
case PIPE_TEXTURE_3D:
|
|
i915_miptree_layout_3d(tex);
|
|
break;
|
|
case PIPE_TEXTURE_CUBE:
|
|
i915_miptree_layout_cube(tex);
|
|
break;
|
|
default:
|
|
assert(0);
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*
|
|
* i945 layout functions
|
|
*/
|
|
|
|
|
|
static void
|
|
i945_miptree_layout_2d(struct i915_texture *tex)
|
|
{
|
|
struct pipe_texture *pt = &tex->base;
|
|
const int align_x = 2, align_y = 4;
|
|
unsigned level;
|
|
unsigned x = 0;
|
|
unsigned y = 0;
|
|
unsigned width = pt->width0;
|
|
unsigned height = pt->height0;
|
|
unsigned nblocksx = pt->nblocksx[0];
|
|
unsigned nblocksy = pt->nblocksy[0];
|
|
|
|
/* used for scanouts that need special layouts */
|
|
if (tex->base.tex_usage & PIPE_TEXTURE_USAGE_PRIMARY)
|
|
if (i915_scanout_layout(tex))
|
|
return;
|
|
|
|
/* for shared buffers we use some very like scanout */
|
|
if (tex->base.tex_usage & PIPE_TEXTURE_USAGE_DISPLAY_TARGET)
|
|
if (i915_display_target_layout(tex))
|
|
return;
|
|
|
|
tex->stride = round_up(pt->nblocksx[0] * pt->block.size, 4);
|
|
|
|
/* May need to adjust pitch to accomodate the placement of
|
|
* the 2nd mipmap level. This occurs when the alignment
|
|
* constraints of mipmap placement push the right edge of the
|
|
* 2nd mipmap level out past the width of its parent.
|
|
*/
|
|
if (pt->last_level > 0) {
|
|
unsigned mip1_nblocksx
|
|
= align(pf_get_nblocksx(&pt->block, u_minify(width, 1)), align_x)
|
|
+ pf_get_nblocksx(&pt->block, u_minify(width, 2));
|
|
|
|
if (mip1_nblocksx > nblocksx)
|
|
tex->stride = mip1_nblocksx * pt->block.size;
|
|
}
|
|
|
|
/* Pitch must be a whole number of dwords
|
|
*/
|
|
tex->stride = align(tex->stride, 64);
|
|
tex->total_nblocksy = 0;
|
|
|
|
for (level = 0; level <= pt->last_level; level++) {
|
|
i915_miptree_set_level_info(tex, level, 1, width, height, 1);
|
|
i915_miptree_set_image_offset(tex, level, 0, x, y);
|
|
|
|
nblocksy = align(nblocksy, align_y);
|
|
|
|
/* Because the images are packed better, the final offset
|
|
* might not be the maximal one:
|
|
*/
|
|
tex->total_nblocksy = MAX2(tex->total_nblocksy, y + nblocksy);
|
|
|
|
/* Layout_below: step right after second mipmap level.
|
|
*/
|
|
if (level == 1) {
|
|
x += align(nblocksx, align_x);
|
|
}
|
|
else {
|
|
y += nblocksy;
|
|
}
|
|
|
|
width = u_minify(width, 1);
|
|
height = u_minify(height, 1);
|
|
nblocksx = pf_get_nblocksx(&pt->block, width);
|
|
nblocksy = pf_get_nblocksy(&pt->block, height);
|
|
}
|
|
}
|
|
|
|
static void
|
|
i945_miptree_layout_3d(struct i915_texture *tex)
|
|
{
|
|
struct pipe_texture *pt = &tex->base;
|
|
unsigned width = pt->width0;
|
|
unsigned height = pt->height0;
|
|
unsigned depth = pt->depth0;
|
|
unsigned nblocksx = pt->nblocksx[0];
|
|
unsigned nblocksy = pt->nblocksy[0];
|
|
unsigned pack_x_pitch, pack_x_nr;
|
|
unsigned pack_y_pitch;
|
|
unsigned level;
|
|
|
|
tex->stride = round_up(pt->nblocksx[0] * pt->block.size, 4);
|
|
tex->total_nblocksy = 0;
|
|
|
|
pack_y_pitch = MAX2(pt->nblocksy[0], 2);
|
|
pack_x_pitch = tex->stride / pt->block.size;
|
|
pack_x_nr = 1;
|
|
|
|
for (level = 0; level <= pt->last_level; level++) {
|
|
int x = 0;
|
|
int y = 0;
|
|
unsigned q, j;
|
|
|
|
i915_miptree_set_level_info(tex, level, depth, width, height, depth);
|
|
|
|
for (q = 0; q < depth;) {
|
|
for (j = 0; j < pack_x_nr && q < depth; j++, q++) {
|
|
i915_miptree_set_image_offset(tex, level, q, x, y + tex->total_nblocksy);
|
|
x += pack_x_pitch;
|
|
}
|
|
|
|
x = 0;
|
|
y += pack_y_pitch;
|
|
}
|
|
|
|
tex->total_nblocksy += y;
|
|
|
|
if (pack_x_pitch > 4) {
|
|
pack_x_pitch >>= 1;
|
|
pack_x_nr <<= 1;
|
|
assert(pack_x_pitch * pack_x_nr * pt->block.size <= tex->stride);
|
|
}
|
|
|
|
if (pack_y_pitch > 2) {
|
|
pack_y_pitch >>= 1;
|
|
}
|
|
|
|
width = u_minify(width, 1);
|
|
height = u_minify(height, 1);
|
|
depth = u_minify(depth, 1);
|
|
nblocksx = pf_get_nblocksx(&pt->block, width);
|
|
nblocksy = pf_get_nblocksy(&pt->block, height);
|
|
}
|
|
}
|
|
|
|
static void
|
|
i945_miptree_layout_cube(struct i915_texture *tex)
|
|
{
|
|
struct pipe_texture *pt = &tex->base;
|
|
unsigned level;
|
|
|
|
const unsigned nblocks = pt->nblocksx[0];
|
|
unsigned face;
|
|
unsigned width = pt->width0;
|
|
unsigned height = pt->height0;
|
|
|
|
/*
|
|
printf("%s %i, %i\n", __FUNCTION__, pt->width0, pt->height0);
|
|
*/
|
|
|
|
assert(width == height); /* cubemap images are square */
|
|
|
|
/*
|
|
* XXX Should only be used for compressed formats. But lets
|
|
* keep this code active just in case.
|
|
*
|
|
* 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 (nblocks > 32)
|
|
tex->stride = round_up(nblocks * pt->block.size * 2, 4);
|
|
else
|
|
tex->stride = 14 * 8 * pt->block.size;
|
|
|
|
tex->total_nblocksy = nblocks * 4;
|
|
|
|
/* Set all the levels to effectively occupy the whole rectangular region.
|
|
*/
|
|
for (level = 0; level <= pt->last_level; level++) {
|
|
i915_miptree_set_level_info(tex, level, 6, width, height, 1);
|
|
width /= 2;
|
|
height /= 2;
|
|
}
|
|
|
|
for (face = 0; face < 6; face++) {
|
|
unsigned x = initial_offsets[face][0] * nblocks;
|
|
unsigned y = initial_offsets[face][1] * nblocks;
|
|
unsigned d = nblocks;
|
|
|
|
#if 0 /* Fix and enable this code for compressed formats */
|
|
if (nblocks == 4 && face >= 4) {
|
|
y = tex->total_height - 4;
|
|
x = (face - 4) * 8;
|
|
}
|
|
else if (nblocks < 4 && (face > 0)) {
|
|
y = tex->total_height - 4;
|
|
x = face * 8;
|
|
}
|
|
#endif
|
|
|
|
for (level = 0; level <= pt->last_level; level++) {
|
|
i915_miptree_set_image_offset(tex, level, face, x, y);
|
|
|
|
d >>= 1;
|
|
|
|
#if 0 /* Fix and enable this code for compressed formats */
|
|
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 = tex->total_height - 4;
|
|
x = (face - 4) * 8;
|
|
break;
|
|
}
|
|
case 2:
|
|
y = tex->total_height - 4;
|
|
x = 16 + face * 8;
|
|
break;
|
|
|
|
case 1:
|
|
x += 48;
|
|
break;
|
|
default:
|
|
#endif
|
|
x += step_offsets[face][0] * d;
|
|
y += step_offsets[face][1] * d;
|
|
#if 0
|
|
break;
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
static boolean
|
|
i945_miptree_layout(struct i915_texture * tex)
|
|
{
|
|
struct pipe_texture *pt = &tex->base;
|
|
|
|
switch (pt->target) {
|
|
case PIPE_TEXTURE_1D:
|
|
case PIPE_TEXTURE_2D:
|
|
i945_miptree_layout_2d(tex);
|
|
break;
|
|
case PIPE_TEXTURE_3D:
|
|
i945_miptree_layout_3d(tex);
|
|
break;
|
|
case PIPE_TEXTURE_CUBE:
|
|
i945_miptree_layout_cube(tex);
|
|
break;
|
|
default:
|
|
assert(0);
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*
|
|
* Screen texture functions
|
|
*/
|
|
|
|
|
|
static struct pipe_texture *
|
|
i915_texture_create(struct pipe_screen *screen,
|
|
const struct pipe_texture *templat)
|
|
{
|
|
struct i915_screen *is = i915_screen(screen);
|
|
struct intel_winsys *iws = is->iws;
|
|
struct i915_texture *tex = CALLOC_STRUCT(i915_texture);
|
|
size_t tex_size;
|
|
unsigned buf_usage = 0;
|
|
|
|
if (!tex)
|
|
return NULL;
|
|
|
|
tex->base = *templat;
|
|
pipe_reference_init(&tex->base.reference, 1);
|
|
tex->base.screen = screen;
|
|
|
|
tex->base.nblocksx[0] = pf_get_nblocksx(&tex->base.block, tex->base.width0);
|
|
tex->base.nblocksy[0] = pf_get_nblocksy(&tex->base.block, tex->base.height0);
|
|
|
|
if (is->is_i945) {
|
|
if (!i945_miptree_layout(tex))
|
|
goto fail;
|
|
} else {
|
|
if (!i915_miptree_layout(tex))
|
|
goto fail;
|
|
}
|
|
|
|
tex_size = tex->stride * tex->total_nblocksy;
|
|
|
|
|
|
|
|
/* for scanouts and cursors, cursors arn't scanouts */
|
|
if (templat->tex_usage & PIPE_TEXTURE_USAGE_PRIMARY && templat->width0 != 64)
|
|
buf_usage = INTEL_NEW_SCANOUT;
|
|
else
|
|
buf_usage = INTEL_NEW_TEXTURE;
|
|
|
|
tex->buffer = iws->buffer_create(iws, tex_size, 64, buf_usage);
|
|
if (!tex->buffer)
|
|
goto fail;
|
|
|
|
/* setup any hw fences */
|
|
if (tex->hw_tiled) {
|
|
assert(tex->sw_tiled == INTEL_TILE_NONE);
|
|
iws->buffer_set_fence_reg(iws, tex->buffer, tex->stride, tex->hw_tiled);
|
|
}
|
|
|
|
|
|
#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
|
|
|
|
return &tex->base;
|
|
|
|
fail:
|
|
FREE(tex);
|
|
return NULL;
|
|
}
|
|
|
|
static struct pipe_texture *
|
|
i915_texture_blanket(struct pipe_screen * screen,
|
|
const struct pipe_texture *base,
|
|
const unsigned *stride,
|
|
struct pipe_buffer *buffer)
|
|
{
|
|
#if 0
|
|
struct i915_texture *tex;
|
|
assert(screen);
|
|
|
|
/* Only supports one type */
|
|
if (base->target != PIPE_TEXTURE_2D ||
|
|
base->last_level != 0 ||
|
|
base->depth0 != 1) {
|
|
return NULL;
|
|
}
|
|
|
|
tex = CALLOC_STRUCT(i915_texture);
|
|
if (!tex)
|
|
return NULL;
|
|
|
|
tex->base = *base;
|
|
pipe_reference_init(&tex->base.reference, 1);
|
|
tex->base.screen = screen;
|
|
|
|
tex->stride = stride[0];
|
|
|
|
i915_miptree_set_level_info(tex, 0, 1, base->width0, base->height0, 1);
|
|
i915_miptree_set_image_offset(tex, 0, 0, 0, 0);
|
|
|
|
pipe_buffer_reference(&tex->buffer, buffer);
|
|
|
|
return &tex->base;
|
|
#else
|
|
return NULL;
|
|
#endif
|
|
}
|
|
|
|
static void
|
|
i915_texture_destroy(struct pipe_texture *pt)
|
|
{
|
|
struct i915_texture *tex = (struct i915_texture *)pt;
|
|
struct intel_winsys *iws = i915_screen(pt->screen)->iws;
|
|
uint i;
|
|
|
|
/*
|
|
DBG("%s deleting %p\n", __FUNCTION__, (void *) tex);
|
|
*/
|
|
|
|
iws->buffer_destroy(iws, tex->buffer);
|
|
|
|
for (i = 0; i < PIPE_MAX_TEXTURE_LEVELS; i++)
|
|
if (tex->image_offset[i])
|
|
FREE(tex->image_offset[i]);
|
|
|
|
FREE(tex);
|
|
}
|
|
|
|
|
|
/*
|
|
* Screen surface functions
|
|
*/
|
|
|
|
|
|
static struct pipe_surface *
|
|
i915_get_tex_surface(struct pipe_screen *screen,
|
|
struct pipe_texture *pt,
|
|
unsigned face, unsigned level, unsigned zslice,
|
|
unsigned flags)
|
|
{
|
|
struct i915_texture *tex = (struct i915_texture *)pt;
|
|
struct pipe_surface *ps;
|
|
unsigned offset; /* in bytes */
|
|
|
|
if (pt->target == PIPE_TEXTURE_CUBE) {
|
|
offset = tex->image_offset[level][face];
|
|
}
|
|
else if (pt->target == PIPE_TEXTURE_3D) {
|
|
offset = tex->image_offset[level][zslice];
|
|
}
|
|
else {
|
|
offset = tex->image_offset[level][0];
|
|
assert(face == 0);
|
|
assert(zslice == 0);
|
|
}
|
|
|
|
ps = CALLOC_STRUCT(pipe_surface);
|
|
if (ps) {
|
|
pipe_reference_init(&ps->reference, 1);
|
|
pipe_texture_reference(&ps->texture, pt);
|
|
ps->format = pt->format;
|
|
ps->width = u_minify(pt->width0, level);
|
|
ps->height = u_minify(pt->height0, level);
|
|
ps->offset = offset;
|
|
ps->usage = flags;
|
|
}
|
|
return ps;
|
|
}
|
|
|
|
static void
|
|
i915_tex_surface_destroy(struct pipe_surface *surf)
|
|
{
|
|
pipe_texture_reference(&surf->texture, NULL);
|
|
FREE(surf);
|
|
}
|
|
|
|
|
|
/*
|
|
* Screen transfer functions
|
|
*/
|
|
|
|
|
|
static struct pipe_transfer*
|
|
i915_get_tex_transfer(struct pipe_screen *screen,
|
|
struct pipe_texture *texture,
|
|
unsigned face, unsigned level, unsigned zslice,
|
|
enum pipe_transfer_usage usage, unsigned x, unsigned y,
|
|
unsigned w, unsigned h)
|
|
{
|
|
struct i915_texture *tex = (struct i915_texture *)texture;
|
|
struct i915_transfer *trans;
|
|
unsigned offset; /* in bytes */
|
|
|
|
if (texture->target == PIPE_TEXTURE_CUBE) {
|
|
offset = tex->image_offset[level][face];
|
|
}
|
|
else if (texture->target == PIPE_TEXTURE_3D) {
|
|
offset = tex->image_offset[level][zslice];
|
|
}
|
|
else {
|
|
offset = tex->image_offset[level][0];
|
|
assert(face == 0);
|
|
assert(zslice == 0);
|
|
}
|
|
|
|
trans = CALLOC_STRUCT(i915_transfer);
|
|
if (trans) {
|
|
pipe_texture_reference(&trans->base.texture, texture);
|
|
trans->base.format = trans->base.format;
|
|
trans->base.x = x;
|
|
trans->base.y = y;
|
|
trans->base.width = w;
|
|
trans->base.height = h;
|
|
trans->base.block = texture->block;
|
|
trans->base.nblocksx = texture->nblocksx[level];
|
|
trans->base.nblocksy = texture->nblocksy[level];
|
|
trans->base.stride = tex->stride;
|
|
trans->offset = offset;
|
|
trans->base.usage = usage;
|
|
}
|
|
return &trans->base;
|
|
}
|
|
|
|
static void *
|
|
i915_transfer_map(struct pipe_screen *screen,
|
|
struct pipe_transfer *transfer)
|
|
{
|
|
struct i915_texture *tex = (struct i915_texture *)transfer->texture;
|
|
struct intel_winsys *iws = i915_screen(tex->base.screen)->iws;
|
|
char *map;
|
|
boolean write = FALSE;
|
|
|
|
if (transfer->usage & PIPE_TRANSFER_WRITE)
|
|
write = TRUE;
|
|
|
|
map = iws->buffer_map(iws, tex->buffer, write);
|
|
if (map == NULL)
|
|
return NULL;
|
|
|
|
return map + i915_transfer(transfer)->offset +
|
|
transfer->y / transfer->block.height * transfer->stride +
|
|
transfer->x / transfer->block.width * transfer->block.size;
|
|
}
|
|
|
|
static void
|
|
i915_transfer_unmap(struct pipe_screen *screen,
|
|
struct pipe_transfer *transfer)
|
|
{
|
|
struct i915_texture *tex = (struct i915_texture *)transfer->texture;
|
|
struct intel_winsys *iws = i915_screen(tex->base.screen)->iws;
|
|
iws->buffer_unmap(iws, tex->buffer);
|
|
}
|
|
|
|
static void
|
|
i915_tex_transfer_destroy(struct pipe_transfer *trans)
|
|
{
|
|
pipe_texture_reference(&trans->texture, NULL);
|
|
FREE(trans);
|
|
}
|
|
|
|
|
|
/*
|
|
* Other texture functions
|
|
*/
|
|
|
|
|
|
void
|
|
i915_init_screen_texture_functions(struct i915_screen *is)
|
|
{
|
|
is->base.texture_create = i915_texture_create;
|
|
is->base.texture_blanket = i915_texture_blanket;
|
|
is->base.texture_destroy = i915_texture_destroy;
|
|
is->base.get_tex_surface = i915_get_tex_surface;
|
|
is->base.tex_surface_destroy = i915_tex_surface_destroy;
|
|
is->base.get_tex_transfer = i915_get_tex_transfer;
|
|
is->base.transfer_map = i915_transfer_map;
|
|
is->base.transfer_unmap = i915_transfer_unmap;
|
|
is->base.tex_transfer_destroy = i915_tex_transfer_destroy;
|
|
}
|
|
|
|
struct pipe_texture *
|
|
i915_texture_blanket_intel(struct pipe_screen *screen,
|
|
struct pipe_texture *base,
|
|
unsigned stride,
|
|
struct intel_buffer *buffer)
|
|
{
|
|
struct i915_texture *tex;
|
|
assert(screen);
|
|
|
|
/* Only supports one type */
|
|
if (base->target != PIPE_TEXTURE_2D ||
|
|
base->last_level != 0 ||
|
|
base->depth0 != 1) {
|
|
return NULL;
|
|
}
|
|
|
|
tex = CALLOC_STRUCT(i915_texture);
|
|
if (!tex)
|
|
return NULL;
|
|
|
|
tex->base = *base;
|
|
pipe_reference_init(&tex->base.reference, 1);
|
|
tex->base.screen = screen;
|
|
|
|
tex->stride = stride;
|
|
|
|
i915_miptree_set_level_info(tex, 0, 1, base->width0, base->height0, 1);
|
|
i915_miptree_set_image_offset(tex, 0, 0, 0, 0);
|
|
|
|
tex->buffer = buffer;
|
|
|
|
return &tex->base;
|
|
}
|
|
|
|
boolean
|
|
i915_get_texture_buffer_intel(struct pipe_texture *texture,
|
|
struct intel_buffer **buffer,
|
|
unsigned *stride)
|
|
{
|
|
struct i915_texture *tex = (struct i915_texture *)texture;
|
|
|
|
if (!texture)
|
|
return FALSE;
|
|
|
|
*stride = tex->stride;
|
|
*buffer = tex->buffer;
|
|
|
|
return TRUE;
|
|
}
|