2012-12-13 04:07:16 +08:00
|
|
|
/*
|
|
|
|
|
* Mesa 3-D graphics library
|
|
|
|
|
*
|
|
|
|
|
* Copyright (C) 2012-2013 LunarG, Inc.
|
|
|
|
|
*
|
|
|
|
|
* 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, sublicense,
|
|
|
|
|
* 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 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 NONINFRINGEMENT. IN NO EVENT SHALL
|
|
|
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS 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:
|
|
|
|
|
* Chia-I Wu <olv@lunarg.com>
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "ilo_screen.h"
|
|
|
|
|
#include "ilo_resource.h"
|
|
|
|
|
|
2013-04-30 15:30:01 +08:00
|
|
|
/* use PIPE_BIND_CUSTOM to indicate MCS */
|
|
|
|
|
#define ILO_BIND_MCS PIPE_BIND_CUSTOM
|
|
|
|
|
|
2013-05-13 15:19:55 +08:00
|
|
|
struct tex_layout {
|
|
|
|
|
const struct ilo_dev_info *dev;
|
|
|
|
|
const struct pipe_resource *templ;
|
2012-12-13 04:44:21 +08:00
|
|
|
|
2013-05-13 15:19:55 +08:00
|
|
|
enum pipe_format format;
|
|
|
|
|
unsigned block_width, block_height, block_size;
|
|
|
|
|
bool compressed;
|
|
|
|
|
bool has_depth, has_stencil;
|
2012-12-13 04:44:21 +08:00
|
|
|
|
2013-05-13 15:19:55 +08:00
|
|
|
enum intel_tiling_mode tiling;
|
|
|
|
|
bool can_be_linear;
|
2012-12-13 04:44:21 +08:00
|
|
|
|
2013-05-13 15:19:55 +08:00
|
|
|
bool array_spacing_full;
|
|
|
|
|
bool interleaved;
|
2012-12-13 04:44:21 +08:00
|
|
|
|
2013-05-13 15:19:55 +08:00
|
|
|
struct {
|
|
|
|
|
int w, h, d;
|
|
|
|
|
struct ilo_texture_slice *slices;
|
|
|
|
|
} levels[PIPE_MAX_TEXTURE_LEVELS];
|
2012-12-13 04:44:21 +08:00
|
|
|
|
2013-05-13 15:19:55 +08:00
|
|
|
int align_i, align_j;
|
|
|
|
|
int qpitch;
|
2012-12-13 04:44:21 +08:00
|
|
|
|
2013-05-13 15:19:55 +08:00
|
|
|
int width, height;
|
|
|
|
|
};
|
2012-12-13 04:44:21 +08:00
|
|
|
|
2013-05-13 15:19:55 +08:00
|
|
|
static void
|
|
|
|
|
tex_layout_init_qpitch(struct tex_layout *layout)
|
2012-12-13 04:44:21 +08:00
|
|
|
{
|
2013-05-13 15:19:55 +08:00
|
|
|
const struct pipe_resource *templ = layout->templ;
|
|
|
|
|
int h0, h1;
|
2012-12-13 04:44:21 +08:00
|
|
|
|
2013-05-13 15:19:55 +08:00
|
|
|
if (templ->array_size <= 1)
|
|
|
|
|
return;
|
2012-12-13 04:44:21 +08:00
|
|
|
|
2013-05-13 15:19:55 +08:00
|
|
|
h0 = align(layout->levels[0].h, layout->align_j);
|
2012-12-13 04:44:21 +08:00
|
|
|
|
2013-05-13 15:19:55 +08:00
|
|
|
if (!layout->array_spacing_full) {
|
|
|
|
|
layout->qpitch = h0;
|
|
|
|
|
return;
|
2012-12-13 04:44:21 +08:00
|
|
|
}
|
|
|
|
|
|
2013-05-13 15:19:55 +08:00
|
|
|
h1 = align(layout->levels[1].h, layout->align_j);
|
2012-12-13 04:44:21 +08:00
|
|
|
|
|
|
|
|
/*
|
2013-05-13 15:19:55 +08:00
|
|
|
* From the Sandy Bridge PRM, volume 1 part 1, page 115:
|
|
|
|
|
*
|
|
|
|
|
* "The following equation is used for surface formats other than
|
|
|
|
|
* compressed textures:
|
|
|
|
|
*
|
|
|
|
|
* QPitch = (h0 + h1 + 11j)"
|
|
|
|
|
*
|
|
|
|
|
* "The equation for compressed textures (BC* and FXT1 surface formats)
|
|
|
|
|
* follows:
|
|
|
|
|
*
|
|
|
|
|
* QPitch = (h0 + h1 + 11j) / 4"
|
|
|
|
|
*
|
|
|
|
|
* "[DevSNB] Errata: Sampler MSAA Qpitch will be 4 greater than the
|
|
|
|
|
* value calculated in the equation above, for every other odd Surface
|
|
|
|
|
* Height starting from 1 i.e. 1,5,9,13"
|
|
|
|
|
*
|
|
|
|
|
* From the Ivy Bridge PRM, volume 1 part 1, page 111-112:
|
|
|
|
|
*
|
|
|
|
|
* "If Surface Array Spacing is set to ARYSPC_FULL (note that the depth
|
|
|
|
|
* buffer and stencil buffer have an implied value of ARYSPC_FULL):
|
|
|
|
|
*
|
|
|
|
|
* QPitch = (h0 + h1 + 12j)
|
|
|
|
|
* QPitch = (h0 + h1 + 12j) / 4 (compressed)
|
|
|
|
|
*
|
|
|
|
|
* (There are many typos or missing words here...)"
|
|
|
|
|
*
|
|
|
|
|
* To access the N-th slice, an offset of (Stride * QPitch * N) is added to
|
|
|
|
|
* the base address. The PRM divides QPitch by 4 for compressed formats
|
|
|
|
|
* because the block height for those formats are 4, and it wants QPitch to
|
|
|
|
|
* mean the number of memory rows, as opposed to texel rows, between
|
|
|
|
|
* slices. Since we use texel rows in tex->slice_offsets, we do not need
|
|
|
|
|
* to divide QPitch by 4.
|
2012-12-13 04:44:21 +08:00
|
|
|
*/
|
2013-05-13 15:19:55 +08:00
|
|
|
layout->qpitch = h0 + h1 +
|
|
|
|
|
((layout->dev->gen >= ILO_GEN(7)) ? 12 : 11) * layout->align_j;
|
2012-12-13 04:44:21 +08:00
|
|
|
|
2013-05-13 15:19:55 +08:00
|
|
|
if (layout->dev->gen == ILO_GEN(6) && templ->nr_samples > 1 &&
|
|
|
|
|
templ->height0 % 4 == 1)
|
|
|
|
|
layout->qpitch += 4;
|
2012-12-13 04:44:21 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2013-05-13 15:19:55 +08:00
|
|
|
tex_layout_init_alignments(struct tex_layout *layout)
|
2012-12-13 04:44:21 +08:00
|
|
|
{
|
2013-05-13 15:19:55 +08:00
|
|
|
const struct pipe_resource *templ = layout->templ;
|
2012-12-13 04:44:21 +08:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* From the Sandy Bridge PRM, volume 1 part 1, page 113:
|
|
|
|
|
*
|
|
|
|
|
* "surface format align_i align_j
|
|
|
|
|
* YUV 4:2:2 formats 4 *see below
|
|
|
|
|
* BC1-5 4 4
|
|
|
|
|
* FXT1 8 4
|
|
|
|
|
* all other formats 4 *see below"
|
|
|
|
|
*
|
|
|
|
|
* "- align_j = 4 for any depth buffer
|
|
|
|
|
* - align_j = 2 for separate stencil buffer
|
|
|
|
|
* - align_j = 4 for any render target surface is multisampled (4x)
|
|
|
|
|
* - align_j = 4 for any render target surface with Surface Vertical
|
|
|
|
|
* Alignment = VALIGN_4
|
|
|
|
|
* - align_j = 2 for any render target surface with Surface Vertical
|
|
|
|
|
* Alignment = VALIGN_2
|
|
|
|
|
* - align_j = 2 for all other render target surface
|
|
|
|
|
* - align_j = 2 for any sampling engine surface with Surface Vertical
|
|
|
|
|
* Alignment = VALIGN_2
|
|
|
|
|
* - align_j = 4 for any sampling engine surface with Surface Vertical
|
|
|
|
|
* Alignment = VALIGN_4"
|
|
|
|
|
*
|
|
|
|
|
* From the Sandy Bridge PRM, volume 4 part 1, page 86:
|
|
|
|
|
*
|
|
|
|
|
* "This field (Surface Vertical Alignment) must be set to VALIGN_2 if
|
|
|
|
|
* the Surface Format is 96 bits per element (BPE)."
|
|
|
|
|
*
|
|
|
|
|
* They can be rephrased as
|
|
|
|
|
*
|
|
|
|
|
* align_i align_j
|
|
|
|
|
* compressed formats block width block height
|
|
|
|
|
* PIPE_FORMAT_S8_UINT 4 2
|
|
|
|
|
* other depth/stencil formats 4 4
|
|
|
|
|
* 4x multisampled 4 4
|
|
|
|
|
* bpp 96 4 2
|
|
|
|
|
* others 4 2 or 4
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* From the Ivy Bridge PRM, volume 1 part 1, page 110:
|
|
|
|
|
*
|
|
|
|
|
* "surface defined by surface format align_i align_j
|
|
|
|
|
* 3DSTATE_DEPTH_BUFFER D16_UNORM 8 4
|
|
|
|
|
* not D16_UNORM 4 4
|
|
|
|
|
* 3DSTATE_STENCIL_BUFFER N/A 8 8
|
|
|
|
|
* SURFACE_STATE BC*, ETC*, EAC* 4 4
|
|
|
|
|
* FXT1 8 4
|
|
|
|
|
* all others (set by SURFACE_STATE)"
|
|
|
|
|
*
|
|
|
|
|
* From the Ivy Bridge PRM, volume 4 part 1, page 63:
|
|
|
|
|
*
|
|
|
|
|
* "- This field (Surface Vertical Aligment) is intended to be set to
|
|
|
|
|
* VALIGN_4 if the surface was rendered as a depth buffer, for a
|
|
|
|
|
* multisampled (4x) render target, or for a multisampled (8x)
|
|
|
|
|
* render target, since these surfaces support only alignment of 4.
|
|
|
|
|
* - Use of VALIGN_4 for other surfaces is supported, but uses more
|
|
|
|
|
* memory.
|
|
|
|
|
* - This field must be set to VALIGN_4 for all tiled Y Render Target
|
|
|
|
|
* surfaces.
|
|
|
|
|
* - Value of 1 is not supported for format YCRCB_NORMAL (0x182),
|
|
|
|
|
* YCRCB_SWAPUVY (0x183), YCRCB_SWAPUV (0x18f), YCRCB_SWAPY (0x190)
|
|
|
|
|
* - If Number of Multisamples is not MULTISAMPLECOUNT_1, this field
|
|
|
|
|
* must be set to VALIGN_4."
|
|
|
|
|
* - VALIGN_4 is not supported for surface format R32G32B32_FLOAT."
|
|
|
|
|
*
|
|
|
|
|
* "- This field (Surface Horizontal Aligment) is intended to be set to
|
|
|
|
|
* HALIGN_8 only if the surface was rendered as a depth buffer with
|
|
|
|
|
* Z16 format or a stencil buffer, since these surfaces support only
|
|
|
|
|
* alignment of 8.
|
|
|
|
|
* - Use of HALIGN_8 for other surfaces is supported, but uses more
|
|
|
|
|
* memory.
|
|
|
|
|
* - This field must be set to HALIGN_4 if the Surface Format is BC*.
|
|
|
|
|
* - This field must be set to HALIGN_8 if the Surface Format is
|
|
|
|
|
* FXT1."
|
|
|
|
|
*
|
|
|
|
|
* They can be rephrased as
|
|
|
|
|
*
|
|
|
|
|
* align_i align_j
|
|
|
|
|
* compressed formats block width block height
|
|
|
|
|
* PIPE_FORMAT_Z16_UNORM 8 4
|
|
|
|
|
* PIPE_FORMAT_S8_UINT 8 8
|
|
|
|
|
* other depth/stencil formats 4 or 8 4
|
|
|
|
|
* 2x or 4x multisampled 4 or 8 4
|
|
|
|
|
* tiled Y 4 or 8 4 (if rt)
|
|
|
|
|
* PIPE_FORMAT_R32G32B32_FLOAT 4 or 8 2
|
|
|
|
|
* others 4 or 8 2 or 4
|
|
|
|
|
*/
|
|
|
|
|
|
2013-05-13 15:19:55 +08:00
|
|
|
if (layout->compressed) {
|
2012-12-13 04:44:21 +08:00
|
|
|
/* this happens to be the case */
|
2013-05-13 15:19:55 +08:00
|
|
|
layout->align_i = layout->block_width;
|
|
|
|
|
layout->align_j = layout->block_height;
|
2012-12-13 04:44:21 +08:00
|
|
|
}
|
2013-05-13 15:19:55 +08:00
|
|
|
else if (layout->has_depth || layout->has_stencil) {
|
|
|
|
|
if (layout->dev->gen >= ILO_GEN(7)) {
|
|
|
|
|
switch (layout->format) {
|
2012-12-13 04:44:21 +08:00
|
|
|
case PIPE_FORMAT_Z16_UNORM:
|
2013-05-13 15:19:55 +08:00
|
|
|
layout->align_i = 8;
|
|
|
|
|
layout->align_j = 4;
|
2012-12-13 04:44:21 +08:00
|
|
|
break;
|
|
|
|
|
case PIPE_FORMAT_S8_UINT:
|
2013-05-13 15:19:55 +08:00
|
|
|
layout->align_i = 8;
|
|
|
|
|
layout->align_j = 8;
|
2012-12-13 04:44:21 +08:00
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
/*
|
|
|
|
|
* From the Ivy Bridge PRM, volume 2 part 1, page 319:
|
|
|
|
|
*
|
|
|
|
|
* "The 3 LSBs of both offsets (Depth Coordinate Offset Y and
|
|
|
|
|
* Depth Coordinate Offset X) must be zero to ensure correct
|
|
|
|
|
* alignment"
|
|
|
|
|
*
|
|
|
|
|
* We will make use of them and setting align_i to 8 help us meet
|
|
|
|
|
* the requirement.
|
|
|
|
|
*/
|
2013-05-13 15:19:55 +08:00
|
|
|
layout->align_i = (templ->last_level > 0) ? 8 : 4;
|
|
|
|
|
layout->align_j = 4;
|
2012-12-13 04:44:21 +08:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
2013-05-13 15:19:55 +08:00
|
|
|
switch (layout->format) {
|
2012-12-13 04:44:21 +08:00
|
|
|
case PIPE_FORMAT_S8_UINT:
|
2013-05-13 15:19:55 +08:00
|
|
|
layout->align_i = 4;
|
|
|
|
|
layout->align_j = 2;
|
2012-12-13 04:44:21 +08:00
|
|
|
break;
|
|
|
|
|
default:
|
2013-05-13 15:19:55 +08:00
|
|
|
layout->align_i = 4;
|
|
|
|
|
layout->align_j = 4;
|
2012-12-13 04:44:21 +08:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
const bool valign_4 = (templ->nr_samples > 1) ||
|
2013-05-13 15:19:55 +08:00
|
|
|
(layout->dev->gen >= ILO_GEN(7) &&
|
|
|
|
|
layout->tiling == INTEL_TILING_Y &&
|
|
|
|
|
(templ->bind & PIPE_BIND_RENDER_TARGET));
|
2012-12-13 04:44:21 +08:00
|
|
|
|
|
|
|
|
if (valign_4)
|
2013-05-13 15:19:55 +08:00
|
|
|
assert(layout->block_size != 12);
|
2012-12-13 04:44:21 +08:00
|
|
|
|
2013-05-13 15:19:55 +08:00
|
|
|
layout->align_i = 4;
|
|
|
|
|
layout->align_j = (valign_4) ? 4 : 2;
|
2012-12-13 04:44:21 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* the fact that align i and j are multiples of block width and height
|
|
|
|
|
* respectively is what makes the size of the bo a multiple of the block
|
|
|
|
|
* size, slices start at block boundaries, and many of the computations
|
|
|
|
|
* work.
|
|
|
|
|
*/
|
2013-05-13 15:19:55 +08:00
|
|
|
assert(layout->align_i % layout->block_width == 0);
|
|
|
|
|
assert(layout->align_j % layout->block_height == 0);
|
2012-12-13 04:44:21 +08:00
|
|
|
|
|
|
|
|
/* make sure align() works */
|
2013-05-13 15:19:55 +08:00
|
|
|
assert(util_is_power_of_two(layout->align_i) &&
|
|
|
|
|
util_is_power_of_two(layout->align_j));
|
|
|
|
|
assert(util_is_power_of_two(layout->block_width) &&
|
|
|
|
|
util_is_power_of_two(layout->block_height));
|
|
|
|
|
}
|
2013-04-30 12:55:18 +08:00
|
|
|
|
2013-05-13 15:19:55 +08:00
|
|
|
static void
|
|
|
|
|
tex_layout_init_levels(struct tex_layout *layout)
|
|
|
|
|
{
|
|
|
|
|
const struct pipe_resource *templ = layout->templ;
|
|
|
|
|
int last_level, lv;
|
2013-04-30 12:14:29 +08:00
|
|
|
|
2012-12-13 04:44:21 +08:00
|
|
|
last_level = templ->last_level;
|
2013-04-30 12:14:29 +08:00
|
|
|
|
|
|
|
|
/* need at least 2 levels to compute full qpitch */
|
2013-05-13 15:19:55 +08:00
|
|
|
if (last_level == 0 && templ->array_size > 1 && layout->array_spacing_full)
|
2012-12-13 04:44:21 +08:00
|
|
|
last_level++;
|
|
|
|
|
|
|
|
|
|
/* compute mip level sizes */
|
|
|
|
|
for (lv = 0; lv <= last_level; lv++) {
|
|
|
|
|
int w, h, d;
|
|
|
|
|
|
|
|
|
|
w = u_minify(templ->width0, lv);
|
|
|
|
|
h = u_minify(templ->height0, lv);
|
|
|
|
|
d = u_minify(templ->depth0, lv);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* From the Sandy Bridge PRM, volume 1 part 1, page 114:
|
|
|
|
|
*
|
|
|
|
|
* "The dimensions of the mip maps are first determined by applying
|
|
|
|
|
* the sizing algorithm presented in Non-Power-of-Two Mipmaps
|
|
|
|
|
* above. Then, if necessary, they are padded out to compression
|
|
|
|
|
* block boundaries."
|
|
|
|
|
*/
|
2013-05-13 15:19:55 +08:00
|
|
|
w = align(w, layout->block_width);
|
|
|
|
|
h = align(h, layout->block_height);
|
2012-12-13 04:44:21 +08:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* From the Sandy Bridge PRM, volume 1 part 1, page 111:
|
|
|
|
|
*
|
|
|
|
|
* "If the surface is multisampled (4x), these values must be
|
|
|
|
|
* adjusted as follows before proceeding:
|
|
|
|
|
*
|
|
|
|
|
* W_L = ceiling(W_L / 2) * 4
|
|
|
|
|
* H_L = ceiling(H_L / 2) * 4"
|
2013-04-30 12:55:18 +08:00
|
|
|
*
|
|
|
|
|
* From the Ivy Bridge PRM, volume 1 part 1, page 108:
|
|
|
|
|
*
|
|
|
|
|
* "If the surface is multisampled and it is a depth or stencil
|
|
|
|
|
* surface or Multisampled Surface StorageFormat in SURFACE_STATE
|
|
|
|
|
* is MSFMT_DEPTH_STENCIL, W_L and H_L must be adjusted as follows
|
|
|
|
|
* before proceeding:
|
|
|
|
|
*
|
|
|
|
|
* #samples W_L = H_L =
|
|
|
|
|
* 2 ceiling(W_L / 2) * 4 HL [no adjustment]
|
|
|
|
|
* 4 ceiling(W_L / 2) * 4 ceiling(H_L / 2) * 4
|
|
|
|
|
* 8 ceiling(W_L / 2) * 8 ceiling(H_L / 2) * 4
|
|
|
|
|
* 16 ceiling(W_L / 2) * 8 ceiling(H_L / 2) * 8"
|
|
|
|
|
*
|
|
|
|
|
* For interleaved samples (4x), where pixels
|
|
|
|
|
*
|
|
|
|
|
* (x, y ) (x+1, y )
|
|
|
|
|
* (x, y+1) (x+1, y+1)
|
|
|
|
|
*
|
|
|
|
|
* would be is occupied by
|
|
|
|
|
*
|
|
|
|
|
* (x, y , si0) (x+1, y , si0) (x, y , si1) (x+1, y , si1)
|
|
|
|
|
* (x, y+1, si0) (x+1, y+1, si0) (x, y+1, si1) (x+1, y+1, si1)
|
|
|
|
|
* (x, y , si2) (x+1, y , si2) (x, y , si3) (x+1, y , si3)
|
|
|
|
|
* (x, y+1, si2) (x+1, y+1, si2) (x, y+1, si3) (x+1, y+1, si3)
|
|
|
|
|
*
|
|
|
|
|
* Thus the need to
|
|
|
|
|
*
|
|
|
|
|
* w = align(w, 2) * 2;
|
|
|
|
|
* y = align(y, 2) * 2;
|
2012-12-13 04:44:21 +08:00
|
|
|
*/
|
2013-05-13 15:19:55 +08:00
|
|
|
if (layout->interleaved) {
|
2013-04-30 12:55:18 +08:00
|
|
|
switch (templ->nr_samples) {
|
|
|
|
|
case 0:
|
|
|
|
|
case 1:
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
w = align(w, 2) * 2;
|
|
|
|
|
break;
|
|
|
|
|
case 4:
|
|
|
|
|
w = align(w, 2) * 2;
|
|
|
|
|
h = align(h, 2) * 2;
|
|
|
|
|
break;
|
|
|
|
|
case 8:
|
|
|
|
|
w = align(w, 2) * 4;
|
|
|
|
|
h = align(h, 2) * 2;
|
|
|
|
|
break;
|
|
|
|
|
case 16:
|
|
|
|
|
w = align(w, 2) * 4;
|
|
|
|
|
h = align(h, 2) * 4;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
assert(!"unsupported sample count");
|
|
|
|
|
break;
|
|
|
|
|
}
|
2012-12-13 04:44:21 +08:00
|
|
|
}
|
|
|
|
|
|
2013-05-13 15:19:55 +08:00
|
|
|
layout->levels[lv].w = w;
|
|
|
|
|
layout->levels[lv].h = h;
|
|
|
|
|
layout->levels[lv].d = d;
|
2012-12-13 04:44:21 +08:00
|
|
|
}
|
2013-05-13 15:19:55 +08:00
|
|
|
}
|
2012-12-13 04:44:21 +08:00
|
|
|
|
2013-05-13 15:19:55 +08:00
|
|
|
static void
|
|
|
|
|
tex_layout_init_spacing(struct tex_layout *layout)
|
|
|
|
|
{
|
|
|
|
|
const struct pipe_resource *templ = layout->templ;
|
2012-12-13 04:44:21 +08:00
|
|
|
|
2013-05-13 15:19:55 +08:00
|
|
|
if (layout->dev->gen >= ILO_GEN(7)) {
|
|
|
|
|
/*
|
|
|
|
|
* It is not explicitly states, but render targets are expected to be
|
|
|
|
|
* UMS/CMS (samples non-interleaved) and depth/stencil buffers are
|
|
|
|
|
* expected to be IMS (samples interleaved).
|
|
|
|
|
*
|
|
|
|
|
* See "Multisampled Surface Storage Format" field of SURFACE_STATE.
|
|
|
|
|
*/
|
|
|
|
|
if (layout->has_depth || layout->has_stencil) {
|
|
|
|
|
layout->interleaved = true;
|
2012-12-13 04:44:21 +08:00
|
|
|
|
|
|
|
|
/*
|
2013-05-13 15:19:55 +08:00
|
|
|
* From the Ivy Bridge PRM, volume 1 part 1, page 111:
|
2013-04-30 12:14:29 +08:00
|
|
|
*
|
2013-05-13 15:19:55 +08:00
|
|
|
* "note that the depth buffer and stencil buffer have an implied
|
|
|
|
|
* value of ARYSPC_FULL"
|
2012-12-13 04:44:21 +08:00
|
|
|
*/
|
2013-05-13 15:19:55 +08:00
|
|
|
layout->array_spacing_full = true;
|
2012-12-13 04:44:21 +08:00
|
|
|
}
|
2013-04-30 12:14:29 +08:00
|
|
|
else {
|
2013-05-13 15:19:55 +08:00
|
|
|
layout->interleaved = false;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* From the Ivy Bridge PRM, volume 4 part 1, page 66:
|
|
|
|
|
*
|
|
|
|
|
* "If Multisampled Surface Storage Format is MSFMT_MSS and
|
|
|
|
|
* Number of Multisamples is not MULTISAMPLECOUNT_1, this field
|
|
|
|
|
* (Surface Array Spacing) must be set to ARYSPC_LOD0."
|
|
|
|
|
*
|
|
|
|
|
* As multisampled resources are not mipmapped, we never use
|
|
|
|
|
* ARYSPC_FULL for them.
|
|
|
|
|
*/
|
|
|
|
|
if (templ->nr_samples > 1)
|
|
|
|
|
assert(templ->last_level == 0);
|
|
|
|
|
layout->array_spacing_full = (templ->last_level > 0);
|
2013-04-30 12:14:29 +08:00
|
|
|
}
|
2012-12-13 04:44:21 +08:00
|
|
|
}
|
2013-05-13 15:19:55 +08:00
|
|
|
else {
|
|
|
|
|
/* GEN6 supports only interleaved samples */
|
|
|
|
|
layout->interleaved = true;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* From the Sandy Bridge PRM, volume 1 part 1, page 115:
|
|
|
|
|
*
|
|
|
|
|
* "The separate stencil buffer does not support mip mapping, thus
|
|
|
|
|
* the storage for LODs other than LOD 0 is not needed. The
|
|
|
|
|
* following QPitch equation applies only to the separate stencil
|
|
|
|
|
* buffer:
|
|
|
|
|
*
|
|
|
|
|
* QPitch = h_0"
|
|
|
|
|
*
|
|
|
|
|
* GEN6 does not support compact spacing otherwise.
|
|
|
|
|
*/
|
|
|
|
|
layout->array_spacing_full = (layout->format != PIPE_FORMAT_S8_UINT);
|
|
|
|
|
}
|
2012-12-13 04:44:21 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2013-05-13 15:19:55 +08:00
|
|
|
tex_layout_init_tiling(struct tex_layout *layout)
|
2012-12-13 04:44:21 +08:00
|
|
|
{
|
2013-05-13 15:19:55 +08:00
|
|
|
const struct pipe_resource *templ = layout->templ;
|
|
|
|
|
const enum pipe_format format = layout->format;
|
|
|
|
|
const unsigned tile_none = 1 << INTEL_TILING_NONE;
|
|
|
|
|
const unsigned tile_x = 1 << INTEL_TILING_X;
|
|
|
|
|
const unsigned tile_y = 1 << INTEL_TILING_Y;
|
|
|
|
|
unsigned valid_tilings = tile_none | tile_x | tile_y;
|
2012-12-13 04:44:21 +08:00
|
|
|
|
2013-05-13 15:19:55 +08:00
|
|
|
/*
|
|
|
|
|
* From the Sandy Bridge PRM, volume 1 part 2, page 32:
|
|
|
|
|
*
|
|
|
|
|
* "Display/Overlay Y-Major not supported.
|
|
|
|
|
* X-Major required for Async Flips"
|
|
|
|
|
*/
|
|
|
|
|
if (unlikely(templ->bind & PIPE_BIND_SCANOUT))
|
|
|
|
|
valid_tilings &= tile_x;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* From the Sandy Bridge PRM, volume 3 part 2, page 158:
|
|
|
|
|
*
|
|
|
|
|
* "The cursor surface address must be 4K byte aligned. The cursor must
|
|
|
|
|
* be in linear memory, it cannot be tiled."
|
|
|
|
|
*/
|
|
|
|
|
if (unlikely(templ->bind & PIPE_BIND_CURSOR))
|
|
|
|
|
valid_tilings &= tile_none;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* From the Ivy Bridge PRM, volume 4 part 1, page 76:
|
|
|
|
|
*
|
|
|
|
|
* "The MCS surface must be stored as Tile Y."
|
|
|
|
|
*/
|
|
|
|
|
if (templ->bind & ILO_BIND_MCS)
|
|
|
|
|
valid_tilings &= tile_y;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* From the Sandy Bridge PRM, volume 2 part 1, page 318:
|
|
|
|
|
*
|
|
|
|
|
* "[DevSNB+]: This field (Tiled Surface) must be set to TRUE. Linear
|
|
|
|
|
* Depth Buffer is not supported."
|
|
|
|
|
*
|
|
|
|
|
* "The Depth Buffer, if tiled, must use Y-Major tiling."
|
|
|
|
|
*
|
|
|
|
|
* From the Sandy Bridge PRM, volume 1 part 2, page 22:
|
|
|
|
|
*
|
|
|
|
|
* "W-Major Tile Format is used for separate stencil."
|
|
|
|
|
*
|
|
|
|
|
* Since the HW does not support W-tiled fencing, we have to do it in the
|
|
|
|
|
* driver.
|
|
|
|
|
*/
|
|
|
|
|
if (templ->bind & PIPE_BIND_DEPTH_STENCIL) {
|
|
|
|
|
switch (format) {
|
|
|
|
|
case PIPE_FORMAT_S8_UINT:
|
|
|
|
|
valid_tilings &= tile_none;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
valid_tilings &= tile_y;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (templ->bind & (PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW)) {
|
|
|
|
|
if (templ->bind & PIPE_BIND_RENDER_TARGET) {
|
|
|
|
|
/*
|
|
|
|
|
* From the Sandy Bridge PRM, volume 1 part 2, page 32:
|
|
|
|
|
*
|
|
|
|
|
* "NOTE: 128BPE Format Color buffer ( render target ) MUST be
|
|
|
|
|
* either TileX or Linear."
|
|
|
|
|
*/
|
|
|
|
|
if (layout->block_size == 16)
|
|
|
|
|
valid_tilings &= ~tile_y;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* From the Ivy Bridge PRM, volume 4 part 1, page 63:
|
|
|
|
|
*
|
|
|
|
|
* "This field (Surface Vertical Aligment) must be set to
|
|
|
|
|
* VALIGN_4 for all tiled Y Render Target surfaces."
|
|
|
|
|
*
|
|
|
|
|
* "VALIGN_4 is not supported for surface format
|
|
|
|
|
* R32G32B32_FLOAT."
|
|
|
|
|
*/
|
|
|
|
|
if (layout->dev->gen >= ILO_GEN(7) && layout->block_size == 12)
|
|
|
|
|
valid_tilings &= ~tile_y;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Also, heuristically set a minimum width/height for enabling tiling.
|
|
|
|
|
*/
|
|
|
|
|
if (templ->width0 < 64 && (valid_tilings & ~tile_x))
|
|
|
|
|
valid_tilings &= ~tile_x;
|
|
|
|
|
|
|
|
|
|
if ((templ->width0 < 32 || templ->height0 < 16) &&
|
|
|
|
|
(templ->width0 < 16 || templ->height0 < 32) &&
|
|
|
|
|
(valid_tilings & ~tile_y))
|
|
|
|
|
valid_tilings &= ~tile_y;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* force linear if we are not sure where the texture is bound to */
|
|
|
|
|
if (valid_tilings & tile_none)
|
|
|
|
|
valid_tilings &= tile_none;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* no conflicting binding flags */
|
|
|
|
|
assert(valid_tilings);
|
|
|
|
|
|
|
|
|
|
/* prefer tiled than linear */
|
|
|
|
|
if (valid_tilings & tile_y)
|
|
|
|
|
layout->tiling = INTEL_TILING_Y;
|
|
|
|
|
else if (valid_tilings & tile_x)
|
|
|
|
|
layout->tiling = INTEL_TILING_X;
|
|
|
|
|
else
|
|
|
|
|
layout->tiling = INTEL_TILING_NONE;
|
|
|
|
|
|
|
|
|
|
layout->can_be_linear = valid_tilings & tile_none;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
tex_layout_init_format(struct tex_layout *layout)
|
|
|
|
|
{
|
|
|
|
|
const struct pipe_resource *templ = layout->templ;
|
|
|
|
|
enum pipe_format format;
|
|
|
|
|
const struct util_format_description *desc;
|
|
|
|
|
|
|
|
|
|
switch (templ->format) {
|
|
|
|
|
case PIPE_FORMAT_ETC1_RGB8:
|
|
|
|
|
format = PIPE_FORMAT_R8G8B8X8_UNORM;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
format = templ->format;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
layout->format = format;
|
|
|
|
|
|
|
|
|
|
layout->block_width = util_format_get_blockwidth(format);
|
|
|
|
|
layout->block_height = util_format_get_blockheight(format);
|
|
|
|
|
layout->block_size = util_format_get_blocksize(format);
|
|
|
|
|
layout->compressed = util_format_is_compressed(format);
|
|
|
|
|
|
|
|
|
|
desc = util_format_description(format);
|
|
|
|
|
layout->has_depth = util_format_has_depth(desc);
|
|
|
|
|
layout->has_stencil = util_format_has_stencil(desc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
tex_layout_init(struct tex_layout *layout,
|
|
|
|
|
struct pipe_screen *screen,
|
|
|
|
|
const struct pipe_resource *templ,
|
|
|
|
|
struct ilo_texture_slice **slices)
|
|
|
|
|
{
|
|
|
|
|
struct ilo_screen *is = ilo_screen(screen);
|
|
|
|
|
|
|
|
|
|
memset(layout, 0, sizeof(*layout));
|
|
|
|
|
|
|
|
|
|
layout->dev = &is->dev;
|
|
|
|
|
layout->templ = templ;
|
|
|
|
|
|
|
|
|
|
/* note that there are dependencies between these functions */
|
|
|
|
|
tex_layout_init_format(layout);
|
|
|
|
|
tex_layout_init_tiling(layout);
|
|
|
|
|
tex_layout_init_spacing(layout);
|
|
|
|
|
tex_layout_init_levels(layout);
|
|
|
|
|
tex_layout_init_alignments(layout);
|
|
|
|
|
tex_layout_init_qpitch(layout);
|
|
|
|
|
|
|
|
|
|
if (slices) {
|
|
|
|
|
int lv;
|
|
|
|
|
|
|
|
|
|
for (lv = 0; lv <= templ->last_level; lv++)
|
|
|
|
|
layout->levels[lv].slices = slices[lv];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool
|
|
|
|
|
tex_layout_force_linear(struct tex_layout *layout)
|
|
|
|
|
{
|
|
|
|
|
if (!layout->can_be_linear)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* we may be able to switch from VALIGN_4 to VALIGN_2 when the layout was
|
|
|
|
|
* Y-tiled, but let's keep it simple
|
|
|
|
|
*/
|
|
|
|
|
layout->tiling = INTEL_TILING_NONE;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Layout a 2D texture.
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
tex_layout_2d(struct tex_layout *layout)
|
|
|
|
|
{
|
|
|
|
|
const struct pipe_resource *templ = layout->templ;
|
|
|
|
|
unsigned int level_x, level_y, num_slices;
|
|
|
|
|
int lv;
|
|
|
|
|
|
|
|
|
|
level_x = 0;
|
|
|
|
|
level_y = 0;
|
|
|
|
|
for (lv = 0; lv <= templ->last_level; lv++) {
|
|
|
|
|
const unsigned int level_w = layout->levels[lv].w;
|
|
|
|
|
const unsigned int level_h = layout->levels[lv].h;
|
2012-12-13 04:44:21 +08:00
|
|
|
int slice;
|
|
|
|
|
|
2013-05-13 15:19:55 +08:00
|
|
|
/* set slice offsets */
|
|
|
|
|
if (layout->levels[lv].slices) {
|
|
|
|
|
for (slice = 0; slice < templ->array_size; slice++) {
|
|
|
|
|
layout->levels[lv].slices[slice].x = level_x;
|
|
|
|
|
/* slices are qpitch apart in Y-direction */
|
|
|
|
|
layout->levels[lv].slices[slice].y =
|
|
|
|
|
level_y + layout->qpitch * slice;
|
|
|
|
|
}
|
2012-12-13 04:44:21 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* extend the size of the monolithic bo to cover this mip level */
|
2013-05-13 15:19:55 +08:00
|
|
|
if (layout->width < level_x + level_w)
|
|
|
|
|
layout->width = level_x + level_w;
|
|
|
|
|
if (layout->height < level_y + level_h)
|
|
|
|
|
layout->height = level_y + level_h;
|
2012-12-13 04:44:21 +08:00
|
|
|
|
|
|
|
|
/* MIPLAYOUT_BELOW */
|
|
|
|
|
if (lv == 1)
|
2013-05-13 15:19:55 +08:00
|
|
|
level_x += align(level_w, layout->align_i);
|
2012-12-13 04:44:21 +08:00
|
|
|
else
|
2013-05-13 15:19:55 +08:00
|
|
|
level_y += align(level_h, layout->align_j);
|
2012-12-13 04:44:21 +08:00
|
|
|
}
|
|
|
|
|
|
2013-04-30 12:55:18 +08:00
|
|
|
num_slices = templ->array_size;
|
|
|
|
|
/* samples of the same index are stored in a slice */
|
2013-05-13 15:19:55 +08:00
|
|
|
if (templ->nr_samples > 1 && !layout->interleaved)
|
2013-04-30 12:55:18 +08:00
|
|
|
num_slices *= templ->nr_samples;
|
|
|
|
|
|
2012-12-13 04:44:21 +08:00
|
|
|
/* we did not take slices into consideration in the computation above */
|
2013-05-13 15:19:55 +08:00
|
|
|
layout->height += layout->qpitch * (num_slices - 1);
|
2012-12-13 04:44:21 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Layout a 3D texture.
|
|
|
|
|
*/
|
|
|
|
|
static void
|
2013-05-13 15:19:55 +08:00
|
|
|
tex_layout_3d(struct tex_layout *layout)
|
2012-12-13 04:44:21 +08:00
|
|
|
{
|
2013-05-13 15:19:55 +08:00
|
|
|
const struct pipe_resource *templ = layout->templ;
|
2012-12-13 04:44:21 +08:00
|
|
|
unsigned int level_y;
|
|
|
|
|
int lv;
|
|
|
|
|
|
|
|
|
|
level_y = 0;
|
|
|
|
|
for (lv = 0; lv <= templ->last_level; lv++) {
|
2013-05-13 15:19:55 +08:00
|
|
|
const unsigned int level_w = layout->levels[lv].w;
|
|
|
|
|
const unsigned int level_h = layout->levels[lv].h;
|
|
|
|
|
const unsigned int level_d = layout->levels[lv].d;
|
|
|
|
|
const unsigned int slice_pitch = align(level_w, layout->align_i);
|
|
|
|
|
const unsigned int slice_qpitch = align(level_h, layout->align_j);
|
2012-12-13 04:44:21 +08:00
|
|
|
const unsigned int num_slices_per_row = 1 << lv;
|
|
|
|
|
int slice;
|
|
|
|
|
|
|
|
|
|
for (slice = 0; slice < level_d; slice += num_slices_per_row) {
|
|
|
|
|
int i;
|
|
|
|
|
|
2013-05-13 15:19:55 +08:00
|
|
|
/* set slice offsets */
|
|
|
|
|
if (layout->levels[lv].slices) {
|
|
|
|
|
for (i = 0; i < num_slices_per_row && slice + i < level_d; i++) {
|
|
|
|
|
layout->levels[lv].slices[slice + i].x = slice_pitch * i;
|
|
|
|
|
layout->levels[lv].slices[slice + i].y = level_y;
|
|
|
|
|
}
|
2012-12-13 04:44:21 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* move on to the next slice row */
|
|
|
|
|
level_y += slice_qpitch;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* rightmost slice */
|
|
|
|
|
slice = MIN2(num_slices_per_row, level_d) - 1;
|
|
|
|
|
|
|
|
|
|
/* extend the size of the monolithic bo to cover this slice */
|
2013-05-13 15:19:55 +08:00
|
|
|
if (layout->width < slice_pitch * slice + level_w)
|
|
|
|
|
layout->width = slice_pitch * slice + level_w;
|
2012-12-13 04:44:21 +08:00
|
|
|
if (lv == templ->last_level)
|
2013-05-13 15:19:55 +08:00
|
|
|
layout->height = (level_y - slice_qpitch) + level_h;
|
2012-12-13 04:44:21 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-13 15:19:55 +08:00
|
|
|
static void
|
|
|
|
|
tex_layout_validate(struct tex_layout *layout)
|
2012-12-13 04:44:21 +08:00
|
|
|
{
|
2013-05-13 15:19:55 +08:00
|
|
|
/*
|
|
|
|
|
* From the Sandy Bridge PRM, volume 1 part 2, page 22:
|
|
|
|
|
*
|
|
|
|
|
* "A 4KB tile is subdivided into 8-high by 8-wide array of Blocks for
|
|
|
|
|
* W-Major Tiles (W Tiles). Each Block is 8 rows by 8 bytes."
|
|
|
|
|
*
|
|
|
|
|
* Since we ask for INTEL_TILING_NONE instead of the non-existent
|
|
|
|
|
* INTEL_TILING_W, we need to manually align the width and height to the
|
|
|
|
|
* tile boundaries.
|
|
|
|
|
*/
|
|
|
|
|
if (layout->templ->format == PIPE_FORMAT_S8_UINT) {
|
|
|
|
|
layout->width = align(layout->width, 64);
|
|
|
|
|
layout->height = align(layout->height, 64);
|
|
|
|
|
}
|
2012-12-13 04:44:21 +08:00
|
|
|
|
2013-05-13 15:19:55 +08:00
|
|
|
assert(layout->width % layout->block_width == 0);
|
|
|
|
|
assert(layout->height % layout->block_height == 0);
|
|
|
|
|
assert(layout->qpitch % layout->block_height == 0);
|
|
|
|
|
}
|
2012-12-13 04:44:21 +08:00
|
|
|
|
2013-05-13 15:19:55 +08:00
|
|
|
static size_t
|
|
|
|
|
tex_layout_estimate_size(const struct tex_layout *layout)
|
|
|
|
|
{
|
|
|
|
|
unsigned stride, height;
|
2012-12-13 04:44:21 +08:00
|
|
|
|
2013-05-13 15:19:55 +08:00
|
|
|
stride = (layout->width / layout->block_width) * layout->block_size;
|
|
|
|
|
height = layout->height / layout->block_height;
|
2012-12-13 04:44:21 +08:00
|
|
|
|
2013-05-13 15:19:55 +08:00
|
|
|
switch (layout->tiling) {
|
2012-12-13 04:44:21 +08:00
|
|
|
case INTEL_TILING_X:
|
2013-05-13 15:19:55 +08:00
|
|
|
stride = align(stride, 512);
|
|
|
|
|
height = align(height, 8);
|
2012-12-13 04:44:21 +08:00
|
|
|
break;
|
|
|
|
|
case INTEL_TILING_Y:
|
2013-05-13 15:19:55 +08:00
|
|
|
stride = align(stride, 128);
|
|
|
|
|
height = align(height, 32);
|
2012-12-13 04:44:21 +08:00
|
|
|
break;
|
|
|
|
|
default:
|
2013-05-13 15:19:55 +08:00
|
|
|
height = align(height, 2);
|
2012-12-13 04:44:21 +08:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-13 15:19:55 +08:00
|
|
|
return stride * height;
|
2012-12-13 04:44:21 +08:00
|
|
|
}
|
|
|
|
|
|
2013-05-13 15:19:55 +08:00
|
|
|
static void
|
|
|
|
|
tex_layout_apply(const struct tex_layout *layout, struct ilo_texture *tex)
|
2012-12-13 04:44:21 +08:00
|
|
|
{
|
2013-05-13 15:19:55 +08:00
|
|
|
tex->bo_format = layout->format;
|
2012-12-13 04:44:21 +08:00
|
|
|
|
2013-05-13 15:19:55 +08:00
|
|
|
/* in blocks */
|
|
|
|
|
tex->bo_width = layout->width / layout->block_width;
|
|
|
|
|
tex->bo_height = layout->height / layout->block_height;
|
|
|
|
|
tex->bo_cpp = layout->block_size;
|
|
|
|
|
tex->tiling = layout->tiling;
|
|
|
|
|
|
|
|
|
|
tex->compressed = layout->compressed;
|
|
|
|
|
tex->block_width = layout->block_width;
|
|
|
|
|
tex->block_height = layout->block_height;
|
|
|
|
|
|
|
|
|
|
tex->halign_8 = (layout->align_i == 8);
|
|
|
|
|
tex->valign_4 = (layout->align_j == 4);
|
|
|
|
|
tex->array_spacing_full = layout->array_spacing_full;
|
|
|
|
|
tex->interleaved = layout->interleaved;
|
|
|
|
|
}
|
2012-12-13 04:44:21 +08:00
|
|
|
|
2013-05-13 15:19:55 +08:00
|
|
|
static void
|
|
|
|
|
tex_free_slices(struct ilo_texture *tex)
|
|
|
|
|
{
|
|
|
|
|
FREE(tex->slice_offsets[0]);
|
|
|
|
|
}
|
2012-12-13 04:44:21 +08:00
|
|
|
|
2013-05-13 15:19:55 +08:00
|
|
|
static bool
|
|
|
|
|
tex_alloc_slices(struct ilo_texture *tex)
|
|
|
|
|
{
|
|
|
|
|
const struct pipe_resource *templ = &tex->base;
|
|
|
|
|
struct ilo_texture_slice *slices;
|
|
|
|
|
int depth, lv;
|
|
|
|
|
|
|
|
|
|
/* sum the depths of all levels */
|
|
|
|
|
depth = 0;
|
|
|
|
|
for (lv = 0; lv <= templ->last_level; lv++)
|
|
|
|
|
depth += u_minify(templ->depth0, lv);
|
2013-04-30 15:30:01 +08:00
|
|
|
|
2012-12-13 04:44:21 +08:00
|
|
|
/*
|
2013-05-13 15:19:55 +08:00
|
|
|
* There are (depth * tex->base.array_size) slices in total. Either depth
|
|
|
|
|
* is one (non-3D) or templ->array_size is one (non-array), but it does
|
|
|
|
|
* not matter.
|
2012-12-13 04:44:21 +08:00
|
|
|
*/
|
2013-05-13 15:19:55 +08:00
|
|
|
slices = CALLOC(depth * templ->array_size, sizeof(*slices));
|
|
|
|
|
if (!slices)
|
|
|
|
|
return false;
|
2012-12-13 04:44:21 +08:00
|
|
|
|
2013-05-13 15:19:55 +08:00
|
|
|
tex->slice_offsets[0] = slices;
|
2012-12-13 04:44:21 +08:00
|
|
|
|
2013-05-13 15:19:55 +08:00
|
|
|
/* point to the respective positions in the buffer */
|
|
|
|
|
for (lv = 1; lv <= templ->last_level; lv++) {
|
|
|
|
|
tex->slice_offsets[lv] = tex->slice_offsets[lv - 1] +
|
|
|
|
|
u_minify(templ->depth0, lv - 1) * templ->array_size;
|
2012-12-13 04:44:21 +08:00
|
|
|
}
|
|
|
|
|
|
2013-05-13 15:19:55 +08:00
|
|
|
return true;
|
2012-12-13 04:44:21 +08:00
|
|
|
}
|
|
|
|
|
|
2013-05-13 15:19:55 +08:00
|
|
|
static struct intel_bo *
|
|
|
|
|
tex_create_bo(const struct ilo_texture *tex,
|
|
|
|
|
const struct winsys_handle *handle)
|
2012-12-13 04:44:21 +08:00
|
|
|
{
|
2013-05-13 15:19:55 +08:00
|
|
|
struct ilo_screen *is = ilo_screen(tex->base.screen);
|
|
|
|
|
const char *name;
|
|
|
|
|
struct intel_bo *bo;
|
2012-12-13 04:44:21 +08:00
|
|
|
|
2013-05-13 15:10:34 +08:00
|
|
|
switch (tex->base.target) {
|
2012-12-13 04:44:21 +08:00
|
|
|
case PIPE_TEXTURE_1D:
|
2013-05-13 15:19:55 +08:00
|
|
|
name = "1D texture";
|
|
|
|
|
break;
|
2012-12-13 04:44:21 +08:00
|
|
|
case PIPE_TEXTURE_2D:
|
2013-05-13 15:19:55 +08:00
|
|
|
name = "2D texture";
|
|
|
|
|
break;
|
|
|
|
|
case PIPE_TEXTURE_3D:
|
|
|
|
|
name = "3D texture";
|
|
|
|
|
break;
|
2012-12-13 04:44:21 +08:00
|
|
|
case PIPE_TEXTURE_CUBE:
|
2013-05-13 15:19:55 +08:00
|
|
|
name = "cube texture";
|
|
|
|
|
break;
|
2012-12-13 04:44:21 +08:00
|
|
|
case PIPE_TEXTURE_RECT:
|
2013-05-13 15:19:55 +08:00
|
|
|
name = "rectangle texture";
|
|
|
|
|
break;
|
2012-12-13 04:44:21 +08:00
|
|
|
case PIPE_TEXTURE_1D_ARRAY:
|
2013-05-13 15:19:55 +08:00
|
|
|
name = "1D array texture";
|
|
|
|
|
break;
|
2012-12-13 04:44:21 +08:00
|
|
|
case PIPE_TEXTURE_2D_ARRAY:
|
2013-05-13 15:19:55 +08:00
|
|
|
name = "2D array texture";
|
2012-12-13 04:44:21 +08:00
|
|
|
break;
|
2013-05-13 15:19:55 +08:00
|
|
|
case PIPE_TEXTURE_CUBE_ARRAY:
|
|
|
|
|
name = "cube array texture";
|
2012-12-13 04:44:21 +08:00
|
|
|
break;
|
|
|
|
|
default:
|
2013-05-13 15:19:55 +08:00
|
|
|
name ="unknown texture";
|
2012-12-13 04:44:21 +08:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-13 15:19:55 +08:00
|
|
|
if (handle) {
|
|
|
|
|
bo = is->winsys->import_handle(is->winsys, name,
|
|
|
|
|
tex->bo_width, tex->bo_height, tex->bo_cpp, handle);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
bo = is->winsys->alloc(is->winsys, name,
|
|
|
|
|
tex->bo_width, tex->bo_height, tex->bo_cpp,
|
|
|
|
|
tex->tiling, tex->bo_flags);
|
2013-04-30 15:30:01 +08:00
|
|
|
}
|
|
|
|
|
|
2013-05-13 15:19:55 +08:00
|
|
|
return bo;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
tex_set_bo(struct ilo_texture *tex, struct intel_bo *bo)
|
|
|
|
|
{
|
|
|
|
|
if (tex->bo)
|
|
|
|
|
tex->bo->unreference(tex->bo);
|
|
|
|
|
|
|
|
|
|
tex->bo = bo;
|
|
|
|
|
|
|
|
|
|
/* winsys may decide to use a different tiling */
|
|
|
|
|
tex->tiling = tex->bo->get_tiling(tex->bo);
|
|
|
|
|
tex->bo_stride = tex->bo->get_pitch(tex->bo);
|
2012-12-13 04:44:21 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2013-05-13 15:19:55 +08:00
|
|
|
tex_destroy(struct ilo_texture *tex)
|
2012-12-13 04:44:21 +08:00
|
|
|
{
|
2013-05-13 15:19:55 +08:00
|
|
|
tex->bo->unreference(tex->bo);
|
|
|
|
|
tex_free_slices(tex);
|
|
|
|
|
FREE(tex);
|
2012-12-13 04:44:21 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct pipe_resource *
|
2013-05-13 15:19:55 +08:00
|
|
|
tex_create(struct pipe_screen *screen,
|
|
|
|
|
const struct pipe_resource *templ,
|
|
|
|
|
const struct winsys_handle *handle)
|
2012-12-13 04:44:21 +08:00
|
|
|
{
|
2013-05-13 15:19:55 +08:00
|
|
|
struct tex_layout layout;
|
2013-05-13 15:10:34 +08:00
|
|
|
struct ilo_texture *tex;
|
2013-05-13 15:19:55 +08:00
|
|
|
struct intel_bo *bo;
|
2012-12-13 04:44:21 +08:00
|
|
|
|
2013-05-13 15:10:34 +08:00
|
|
|
tex = CALLOC_STRUCT(ilo_texture);
|
|
|
|
|
if (!tex)
|
2012-12-13 04:44:21 +08:00
|
|
|
return NULL;
|
|
|
|
|
|
2013-05-13 15:10:34 +08:00
|
|
|
tex->base = *templ;
|
|
|
|
|
tex->base.screen = screen;
|
|
|
|
|
pipe_reference_init(&tex->base.reference, 1);
|
2012-12-13 04:44:21 +08:00
|
|
|
|
2013-05-13 15:19:55 +08:00
|
|
|
if (!tex_alloc_slices(tex)) {
|
2013-05-13 15:10:34 +08:00
|
|
|
FREE(tex);
|
2012-12-13 04:44:21 +08:00
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-13 15:19:55 +08:00
|
|
|
tex->imported = (handle != NULL);
|
|
|
|
|
|
|
|
|
|
if (tex->base.bind & (PIPE_BIND_DEPTH_STENCIL |
|
|
|
|
|
PIPE_BIND_RENDER_TARGET))
|
|
|
|
|
tex->bo_flags |= INTEL_ALLOC_FOR_RENDER;
|
|
|
|
|
|
|
|
|
|
tex_layout_init(&layout, screen, templ, tex->slice_offsets);
|
|
|
|
|
|
|
|
|
|
switch (templ->target) {
|
|
|
|
|
case PIPE_TEXTURE_1D:
|
|
|
|
|
case PIPE_TEXTURE_2D:
|
|
|
|
|
case PIPE_TEXTURE_CUBE:
|
|
|
|
|
case PIPE_TEXTURE_RECT:
|
|
|
|
|
case PIPE_TEXTURE_1D_ARRAY:
|
|
|
|
|
case PIPE_TEXTURE_2D_ARRAY:
|
|
|
|
|
case PIPE_TEXTURE_CUBE_ARRAY:
|
|
|
|
|
tex_layout_2d(&layout);
|
|
|
|
|
break;
|
|
|
|
|
case PIPE_TEXTURE_3D:
|
|
|
|
|
tex_layout_3d(&layout);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
assert(!"unknown resource target");
|
|
|
|
|
break;
|
|
|
|
|
}
|
2012-12-13 04:44:21 +08:00
|
|
|
|
2013-05-13 15:19:55 +08:00
|
|
|
tex_layout_validate(&layout);
|
|
|
|
|
|
|
|
|
|
/* make sure the bo can be mapped through GTT if tiled */
|
|
|
|
|
if (layout.tiling != INTEL_TILING_NONE) {
|
|
|
|
|
/*
|
|
|
|
|
* Usually only the first 256MB of the GTT is mappable.
|
|
|
|
|
*
|
|
|
|
|
* See also how intel_context::max_gtt_map_object_size is calculated.
|
|
|
|
|
*/
|
|
|
|
|
const size_t mappable_gtt_size = 256 * 1024 * 1024;
|
|
|
|
|
const size_t size = tex_layout_estimate_size(&layout);
|
|
|
|
|
|
|
|
|
|
/* be conservative */
|
|
|
|
|
if (size > mappable_gtt_size / 4)
|
|
|
|
|
tex_layout_force_linear(&layout);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tex_layout_apply(&layout, tex);
|
|
|
|
|
|
|
|
|
|
bo = tex_create_bo(tex, handle);
|
|
|
|
|
if (!bo) {
|
|
|
|
|
tex_free_slices(tex);
|
2013-05-13 15:10:34 +08:00
|
|
|
FREE(tex);
|
2012-12-13 04:44:21 +08:00
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-13 15:19:55 +08:00
|
|
|
tex_set_bo(tex, bo);
|
|
|
|
|
|
2013-05-13 15:10:34 +08:00
|
|
|
return &tex->base;
|
2012-12-13 04:44:21 +08:00
|
|
|
}
|
|
|
|
|
|
2013-05-13 15:19:55 +08:00
|
|
|
static bool
|
|
|
|
|
tex_get_handle(struct ilo_texture *tex, struct winsys_handle *handle)
|
|
|
|
|
{
|
|
|
|
|
int err;
|
|
|
|
|
|
|
|
|
|
err = tex->bo->export_handle(tex->bo, handle);
|
|
|
|
|
|
|
|
|
|
return !err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Estimate the texture size. For large textures, the errors should be pretty
|
|
|
|
|
* small.
|
|
|
|
|
*/
|
|
|
|
|
static size_t
|
|
|
|
|
tex_estimate_size(struct pipe_screen *screen,
|
|
|
|
|
const struct pipe_resource *templ)
|
|
|
|
|
{
|
|
|
|
|
struct tex_layout layout;
|
|
|
|
|
|
|
|
|
|
tex_layout_init(&layout, screen, templ, NULL);
|
|
|
|
|
|
|
|
|
|
switch (templ->target) {
|
|
|
|
|
case PIPE_TEXTURE_3D:
|
|
|
|
|
tex_layout_3d(&layout);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
tex_layout_2d(&layout);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tex_layout_validate(&layout);
|
|
|
|
|
|
|
|
|
|
return tex_layout_estimate_size(&layout);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct intel_bo *
|
|
|
|
|
buf_create_bo(const struct ilo_buffer *buf)
|
|
|
|
|
{
|
|
|
|
|
struct ilo_screen *is = ilo_screen(buf->base.screen);
|
|
|
|
|
const char *name;
|
|
|
|
|
|
|
|
|
|
switch (buf->base.bind) {
|
|
|
|
|
case PIPE_BIND_VERTEX_BUFFER:
|
|
|
|
|
name = "vertex buffer";
|
|
|
|
|
break;
|
|
|
|
|
case PIPE_BIND_INDEX_BUFFER:
|
|
|
|
|
name = "index buffer";
|
|
|
|
|
break;
|
|
|
|
|
case PIPE_BIND_CONSTANT_BUFFER:
|
|
|
|
|
name = "constant buffer";
|
|
|
|
|
break;
|
|
|
|
|
case PIPE_BIND_STREAM_OUTPUT:
|
|
|
|
|
name = "stream output";
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
name = "unknown buffer";
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return is->winsys->alloc_buffer(is->winsys,
|
|
|
|
|
name, buf->bo_size, buf->bo_flags);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
buf_set_bo(struct ilo_buffer *buf, struct intel_bo *bo)
|
|
|
|
|
{
|
|
|
|
|
if (buf->bo)
|
|
|
|
|
buf->bo->unreference(buf->bo);
|
|
|
|
|
|
|
|
|
|
buf->bo = bo;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
buf_destroy(struct ilo_buffer *buf)
|
|
|
|
|
{
|
|
|
|
|
buf->bo->unreference(buf->bo);
|
|
|
|
|
FREE(buf);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct pipe_resource *
|
|
|
|
|
buf_create(struct pipe_screen *screen, const struct pipe_resource *templ)
|
|
|
|
|
{
|
|
|
|
|
struct ilo_buffer *buf;
|
|
|
|
|
struct intel_bo *bo;
|
|
|
|
|
|
|
|
|
|
buf = CALLOC_STRUCT(ilo_buffer);
|
|
|
|
|
if (!buf)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
buf->base = *templ;
|
|
|
|
|
buf->base.screen = screen;
|
|
|
|
|
pipe_reference_init(&buf->base.reference, 1);
|
|
|
|
|
|
|
|
|
|
buf->bo_size = templ->width0;
|
|
|
|
|
buf->bo_flags = 0;
|
|
|
|
|
|
|
|
|
|
bo = buf_create_bo(buf);
|
|
|
|
|
if (!bo) {
|
|
|
|
|
FREE(buf);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
buf_set_bo(buf, bo);
|
|
|
|
|
|
|
|
|
|
return &buf->base;
|
|
|
|
|
}
|
|
|
|
|
|
2012-12-13 04:44:21 +08:00
|
|
|
static boolean
|
|
|
|
|
ilo_can_create_resource(struct pipe_screen *screen,
|
|
|
|
|
const struct pipe_resource *templ)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* We do not know if we will fail until we try to allocate the bo.
|
|
|
|
|
* So just set a limit on the texture size.
|
|
|
|
|
*/
|
|
|
|
|
const size_t max_size = 1 * 1024 * 1024 * 1024;
|
2013-05-13 15:19:55 +08:00
|
|
|
size_t size;
|
|
|
|
|
|
|
|
|
|
if (templ->target == PIPE_BUFFER)
|
|
|
|
|
size = templ->width0;
|
|
|
|
|
else
|
|
|
|
|
size = tex_estimate_size(screen, templ);
|
2012-12-13 04:44:21 +08:00
|
|
|
|
|
|
|
|
return (size <= max_size);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct pipe_resource *
|
|
|
|
|
ilo_resource_create(struct pipe_screen *screen,
|
|
|
|
|
const struct pipe_resource *templ)
|
|
|
|
|
{
|
2013-05-13 15:19:55 +08:00
|
|
|
if (templ->target == PIPE_BUFFER)
|
|
|
|
|
return buf_create(screen, templ);
|
|
|
|
|
else
|
|
|
|
|
return tex_create(screen, templ, NULL);
|
2012-12-13 04:44:21 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct pipe_resource *
|
|
|
|
|
ilo_resource_from_handle(struct pipe_screen *screen,
|
|
|
|
|
const struct pipe_resource *templ,
|
|
|
|
|
struct winsys_handle *handle)
|
|
|
|
|
{
|
2013-05-13 15:19:55 +08:00
|
|
|
if (templ->target == PIPE_BUFFER)
|
|
|
|
|
return NULL;
|
|
|
|
|
else
|
|
|
|
|
return tex_create(screen, templ, handle);
|
2012-12-13 04:44:21 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static boolean
|
|
|
|
|
ilo_resource_get_handle(struct pipe_screen *screen,
|
2013-05-13 15:10:34 +08:00
|
|
|
struct pipe_resource *res,
|
2012-12-13 04:44:21 +08:00
|
|
|
struct winsys_handle *handle)
|
|
|
|
|
{
|
2013-05-13 15:19:55 +08:00
|
|
|
if (res->target == PIPE_BUFFER)
|
|
|
|
|
return false;
|
|
|
|
|
else
|
|
|
|
|
return tex_get_handle(ilo_texture(res), handle);
|
2012-12-13 04:44:21 +08:00
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
ilo_resource_destroy(struct pipe_screen *screen,
|
2013-05-13 15:10:34 +08:00
|
|
|
struct pipe_resource *res)
|
2012-12-13 04:44:21 +08:00
|
|
|
{
|
2013-05-13 15:19:55 +08:00
|
|
|
if (res->target == PIPE_BUFFER)
|
|
|
|
|
buf_destroy(ilo_buffer(res));
|
|
|
|
|
else
|
|
|
|
|
tex_destroy(ilo_texture(res));
|
2012-12-13 04:44:21 +08:00
|
|
|
}
|
|
|
|
|
|
2012-12-13 04:07:16 +08:00
|
|
|
/**
|
|
|
|
|
* Initialize resource-related functions.
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
ilo_init_resource_functions(struct ilo_screen *is)
|
|
|
|
|
{
|
2012-12-13 04:44:21 +08:00
|
|
|
is->base.can_create_resource = ilo_can_create_resource;
|
|
|
|
|
is->base.resource_create = ilo_resource_create;
|
|
|
|
|
is->base.resource_from_handle = ilo_resource_from_handle;
|
|
|
|
|
is->base.resource_get_handle = ilo_resource_get_handle;
|
|
|
|
|
is->base.resource_destroy = ilo_resource_destroy;
|
2012-12-13 04:07:16 +08:00
|
|
|
}
|
|
|
|
|
|
2013-05-13 15:19:55 +08:00
|
|
|
bool
|
|
|
|
|
ilo_buffer_alloc_bo(struct ilo_buffer *buf)
|
|
|
|
|
{
|
|
|
|
|
struct intel_bo *bo;
|
|
|
|
|
|
|
|
|
|
bo = buf_create_bo(buf);
|
|
|
|
|
if (!bo)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
buf_set_bo(buf, bo);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
ilo_texture_alloc_bo(struct ilo_texture *tex)
|
|
|
|
|
{
|
|
|
|
|
struct intel_bo *bo;
|
|
|
|
|
|
|
|
|
|
/* a shared bo cannot be reallocated */
|
|
|
|
|
if (tex->imported)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
bo = tex_create_bo(tex, NULL);
|
|
|
|
|
if (!bo)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
tex_set_bo(tex, bo);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2012-12-13 05:23:34 +08:00
|
|
|
/**
|
|
|
|
|
* Return the offset (in bytes) to a slice within the bo.
|
|
|
|
|
*
|
|
|
|
|
* When tile_aligned is true, the offset is to the tile containing the start
|
|
|
|
|
* address of the slice. x_offset and y_offset are offsets (in pixels) from
|
|
|
|
|
* the tile start to slice start. x_offset is always a multiple of 4 and
|
|
|
|
|
* y_offset is always a multiple of 2.
|
|
|
|
|
*/
|
|
|
|
|
unsigned
|
2013-05-13 15:10:34 +08:00
|
|
|
ilo_texture_get_slice_offset(const struct ilo_texture *tex,
|
|
|
|
|
int level, int slice, bool tile_aligned,
|
|
|
|
|
unsigned *x_offset, unsigned *y_offset)
|
2012-12-13 05:23:34 +08:00
|
|
|
{
|
2013-05-13 15:10:34 +08:00
|
|
|
const unsigned x = tex->slice_offsets[level][slice].x / tex->block_width;
|
|
|
|
|
const unsigned y = tex->slice_offsets[level][slice].y / tex->block_height;
|
2012-12-13 05:23:34 +08:00
|
|
|
unsigned tile_w, tile_h, tile_size, row_size;
|
|
|
|
|
unsigned slice_offset;
|
|
|
|
|
|
|
|
|
|
/* see the Sandy Bridge PRM, volume 1 part 2, page 24 */
|
|
|
|
|
|
2013-05-13 15:10:34 +08:00
|
|
|
switch (tex->tiling) {
|
2012-12-13 05:23:34 +08:00
|
|
|
case INTEL_TILING_NONE:
|
2013-05-13 15:10:34 +08:00
|
|
|
tile_w = tex->bo_cpp;
|
2012-12-13 05:23:34 +08:00
|
|
|
tile_h = 1;
|
|
|
|
|
break;
|
|
|
|
|
case INTEL_TILING_X:
|
|
|
|
|
tile_w = 512;
|
|
|
|
|
tile_h = 8;
|
|
|
|
|
break;
|
|
|
|
|
case INTEL_TILING_Y:
|
|
|
|
|
tile_w = 128;
|
|
|
|
|
tile_h = 32;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
assert(!"unknown tiling");
|
2013-05-13 15:10:34 +08:00
|
|
|
tile_w = tex->bo_cpp;
|
2012-12-13 05:23:34 +08:00
|
|
|
tile_h = 1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tile_size = tile_w * tile_h;
|
2013-05-13 15:10:34 +08:00
|
|
|
row_size = tex->bo_stride * tile_h;
|
2012-12-13 05:23:34 +08:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* for non-tiled resources, this is equivalent to
|
|
|
|
|
*
|
2013-05-13 15:10:34 +08:00
|
|
|
* slice_offset = y * tex->bo_stride + x * tex->bo_cpp;
|
2012-12-13 05:23:34 +08:00
|
|
|
*/
|
|
|
|
|
slice_offset =
|
2013-05-13 15:10:34 +08:00
|
|
|
row_size * (y / tile_h) + tile_size * (x * tex->bo_cpp / tile_w);
|
2012-12-13 05:23:34 +08:00
|
|
|
|
|
|
|
|
/*
|
2013-05-13 15:10:34 +08:00
|
|
|
* Since tex->bo_stride is a multiple of tile_w, slice_offset should be
|
2012-12-13 05:23:34 +08:00
|
|
|
* aligned at this point.
|
|
|
|
|
*/
|
|
|
|
|
assert(slice_offset % tile_size == 0);
|
|
|
|
|
|
|
|
|
|
if (tile_aligned) {
|
|
|
|
|
/*
|
|
|
|
|
* because of the possible values of align_i and align_j in
|
|
|
|
|
* layout_tex_init(), x_offset must be a multiple of 4 and y_offset must
|
|
|
|
|
* be a multiple of 2.
|
|
|
|
|
*/
|
|
|
|
|
if (x_offset) {
|
2013-05-13 15:10:34 +08:00
|
|
|
assert(tile_w % tex->bo_cpp == 0);
|
|
|
|
|
*x_offset = (x % (tile_w / tex->bo_cpp)) * tex->block_width;
|
2012-12-13 05:23:34 +08:00
|
|
|
assert(*x_offset % 4 == 0);
|
|
|
|
|
}
|
|
|
|
|
if (y_offset) {
|
2013-05-13 15:10:34 +08:00
|
|
|
*y_offset = (y % tile_h) * tex->block_height;
|
2012-12-13 05:23:34 +08:00
|
|
|
assert(*y_offset % 2 == 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
2013-05-13 15:10:34 +08:00
|
|
|
const unsigned tx = (x * tex->bo_cpp) % tile_w;
|
2012-12-13 05:23:34 +08:00
|
|
|
const unsigned ty = y % tile_h;
|
|
|
|
|
|
2013-05-13 15:10:34 +08:00
|
|
|
switch (tex->tiling) {
|
2012-12-13 05:23:34 +08:00
|
|
|
case INTEL_TILING_NONE:
|
|
|
|
|
assert(tx == 0 && ty == 0);
|
|
|
|
|
break;
|
|
|
|
|
case INTEL_TILING_X:
|
|
|
|
|
slice_offset += tile_w * ty + tx;
|
|
|
|
|
break;
|
|
|
|
|
case INTEL_TILING_Y:
|
|
|
|
|
slice_offset += tile_h * 16 * (tx / 16) + ty * 16 + (tx % 16);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (x_offset)
|
|
|
|
|
*x_offset = 0;
|
|
|
|
|
if (y_offset)
|
|
|
|
|
*y_offset = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return slice_offset;
|
|
|
|
|
}
|