<p dir="ltr"><br>
On Jul 24, 2015 8:02 AM, "Francisco Jerez" <<a href="mailto:currojerez@riseup.net">currojerez@riseup.net</a>> wrote:<br>
><br>
> Jason Ekstrand <<a href="mailto:jason@jlekstrand.net">jason@jlekstrand.net</a>> writes:<br>
><br>
> > On Fri, Jul 24, 2015 at 7:39 AM, Francisco Jerez <<a href="mailto:currojerez@riseup.net">currojerez@riseup.net</a>> wrote:<br>
> >> Jason Ekstrand <<a href="mailto:jason@jlekstrand.net">jason@jlekstrand.net</a>> writes:<br>
> >><br>
> >>> On Jul 24, 2015 4:00 AM, "Francisco Jerez" <<a href="mailto:currojerez@riseup.net">currojerez@riseup.net</a>> wrote:<br>
> >>>><br>
> >>>> Jason Ekstrand <<a href="mailto:jason@jlekstrand.net">jason@jlekstrand.net</a>> writes:<br>
> >>>><br>
> >>>> > Ok, I've looked through this again and convinced myself that it's<br>
> >>>> > *mostly* correct. I am a bit skeptical of the address swizzling for<br>
> >>>> > Y-major tiling.<br>
> >>>> ><br>
> >>>> > I've also included some comments that I'd like to see added (assuming<br>
> >>>> > they're correct). Sometimes it's easier to write helpful comments if<br>
> >>>> > the person who is confused does the writing. :-)<br>
> >>>> ><br>
> >>>><br>
> >>>> Thanks! This will save me quite some guesswork, I'll add them to the<br>
> >>>> patch.<br>
> >>>><br>
> >>>> > Also, I'd just like to say that I'm terribly impressed after reading<br>
> >>>> > through this. You managed to handle an amazing number of cases<br>
> >>>> > without so much as a single if statement or predicated instruction.<br>
> >>>> > My hat's off to you sir.<br>
> >>>> ><br>
> >>>> Hah, I feel flattered. :)<br>
> >>>><br>
> >>>> > Modulo Y-tiling and comments,<br>
> >>>> ><br>
> >>>> > Reviewed-by: Jason Ekstrand <<a href="mailto:jason.ekstrand@intel.com">jason.ekstrand@intel.com</a>><br>
> >>>> ><br>
> >>>> > On Tue, Jul 21, 2015 at 9:38 AM, Francisco Jerez <<a href="mailto:currojerez@riseup.net">currojerez@riseup.net</a>><br>
> >>> wrote:<br>
> >>>> >> Define a function to calculate the memory address of the image<br>
> >>>> >> location given by a vector of coordinates. This is required in cases<br>
> >>>> >> where we need to fall back to untyped surface access, which take a raw<br>
> >>>> >> memory offset and know nothing about surface coordinates, type<br>
> >>>> >> conversion or memory tiling and swizzling. They are still useful<br>
> >>>> >> because typed surface reads don't support any 64 or 128-bit formats on<br>
> >>>> >> IVB, and they don't support any 128-bit formats on HSW and BDW.<br>
> >>>> >><br>
> >>>> >> The tiling algorithm is implemented based on a number of parameters<br>
> >>>> >> which are passed in as uniforms and determine whether the surface<br>
> >>>> >> layout is X-tiled, Y-tiled or untiled. This allows binding surfaces<br>
> >>>> >> of different tiling layouts to the pipeline without recompiling the<br>
> >>>> >> program.<br>
> >>>> >><br>
> >>>> >> v2: Drop VEC4 suport.<br>
> >>>> >> v3: Rebase.<br>
> >>>> >> ---<br>
> >>>> >> .../drivers/dri/i965/brw_fs_surface_builder.cpp | 108<br>
> >>> +++++++++++++++++++++<br>
> >>>> >> 1 file changed, 108 insertions(+)<br>
> >>>> >><br>
> >>>> >> diff --git a/src/mesa/drivers/dri/i965/brw_fs_surface_builder.cpp<br>
> >>> b/src/mesa/drivers/dri/i965/brw_fs_surface_builder.cpp<br>
> >>>> >> index 5ee04de..0c879db 100644<br>
> >>>> >> --- a/src/mesa/drivers/dri/i965/brw_fs_surface_builder.cpp<br>
> >>>> >> +++ b/src/mesa/drivers/dri/i965/brw_fs_surface_builder.cpp<br>
> >>>> >> @@ -215,4 +215,112 @@ namespace {<br>
> >>>> >> return BRW_PREDICATE_NORMAL;<br>
> >>>> >> }<br>
> >>>> >> }<br>
> >>>> >> +<br>
> >>>> >> + namespace image_coordinates {<br>
> >>>> >> + /**<br>
> >>>> >> + * Calculate the offset in memory of the texel given by \p<br>
> >>> coord.<br>
> >>>> >> + *<br>
> >>>> >> + * This is meant to be used with untyped surface messages to<br>
> >>> access a<br>
> >>>> >> + * tiled surface, what involves taking into account the tiling<br>
> >>> and<br>
> >>>> >> + * swizzling modes of the surface manually so it will hopefully<br>
> >>> not<br>
> >>>> >> + * happen very often.<br>
> >>>> >> + */<br>
> >>>> >> + fs_reg<br>
> >>>> >> + emit_address_calculation(const fs_builder &bld, const fs_reg<br>
> >>> &image,<br>
> >>>> >> + const fs_reg &coord, unsigned dims)<br>
> >>>> >> + {<br>
> >>>> >> + const brw_device_info *devinfo = bld.shader->devinfo;<br>
> >>>> >> + const fs_reg off = offset(image, bld,<br>
> >>> BRW_IMAGE_PARAM_OFFSET_OFFSET);<br>
> >>>> >> + const fs_reg stride = offset(image, bld,<br>
> >>> BRW_IMAGE_PARAM_STRIDE_OFFSET);<br>
> >>>> >> + const fs_reg tile = offset(image, bld,<br>
> >>> BRW_IMAGE_PARAM_TILING_OFFSET);<br>
> >>>> >> + const fs_reg swz = offset(image, bld,<br>
> >>> BRW_IMAGE_PARAM_SWIZZLING_OFFSET);<br>
> >>>> >> + const fs_reg addr = bld.vgrf(BRW_REGISTER_TYPE_UD, 2);<br>
> >>>> >> + const fs_reg tmp = bld.vgrf(BRW_REGISTER_TYPE_UD, 2);<br>
> >>>> >> + const fs_reg minor = bld.vgrf(BRW_REGISTER_TYPE_UD, 2);<br>
> >>>> >> + const fs_reg major = bld.vgrf(BRW_REGISTER_TYPE_UD, 2);<br>
> >>>> >> + const fs_reg dst = bld.vgrf(BRW_REGISTER_TYPE_UD);<br>
> >>>> >> +<br>
> >>>> >> + /* Shift the coordinates by the fixed surface offset. */<br>
> >>>> >> + for (unsigned c = 0; c < 2; ++c)<br>
> >>>> >> + bld.ADD(offset(addr, bld, c), offset(off, bld, c),<br>
> >>>> >> + (c < dims ?<br>
> >>>> >> + offset(retype(coord, BRW_REGISTER_TYPE_UD), bld,<br>
> >>> c) :<br>
> >>>> >> + fs_reg(0)));<br>
> >>>> >> +<br>
> >>>> >> + if (dims > 2) {<br>
> >>>> >> + /* Decompose z into a major (tmp.y) and a minor (tmp.x)<br>
> >>>> >> + * index.<br>
> >>>> ><br>
> >>>> > Please add a comment:<br>
> >>>> > /*<br>
> >>>> > The layout of 3-D textures in memory is sort-of like a tiling format.<br>
> >>>> > At each miplevel, the slices are arranged in rows of 2^level slices<br>
> >>>> > per row. The slice row is stored in tmp.y and the slice within the<br>
> >>>> > row is stored in tmp.x. The layout of 2-D array textures is much<br>
> >>>> > simpler. Each slice of the texture is storred as a 2-D texture with<br>
> >>>> > all its miplevels and then one qpitch later, the next slice is stored<br>
> >>>> > with its miplevels. This code handles both by passing in the miplevel<br>
> >>>> > as tile[2] for 3-D textures and 0 in tile[2] for 2-D array textures.<br>
> >>>> > */<br>
> >>>><br>
> >>>> Note that depending on the ARYSPC_LOD0 surface state flag array textures<br>
> >>>> may also be interleaved in the opposite way -- All slices for LOD0, then<br>
> >>>> all slices for LOD1, and so on. We probably don't hit this case<br>
> >>>> currently because MS images are not exposed but it's handled in the same<br>
> >>>> way by setting stride[3] to the spacing between slices. I'll add that<br>
> >>>> to your comment.<br>
> >>>><br>
> >>>> >> + */<br>
> >>>> >> + bld.BFE(offset(tmp, bld, 0), offset(tile, bld, 2),<br>
> >>> fs_reg(0),<br>
> >>>> >> + offset(retype(coord, BRW_REGISTER_TYPE_UD), bld,<br>
> >>> 2));<br>
> >>>> >> + bld.SHR(offset(tmp, bld, 1),<br>
> >>>> >> + offset(retype(coord, BRW_REGISTER_TYPE_UD), bld,<br>
> >>> 2),<br>
> >>>> >> + offset(tile, bld, 2));<br>
> >>>> >> +<br>
> >>>> >> + /* Take into account the horizontal (tmp.x) and vertical<br>
> >>> (tmp.y)<br>
> >>>> >> + * slice offset.<br>
> >>>> >> + */<br>
> >>>> >> + for (unsigned c = 0; c < 2; ++c) {<br>
> >>>> >> + bld.MUL(offset(tmp, bld, c),<br>
> >>>> >> + offset(stride, bld, 2 + c), offset(tmp, bld,<br>
> >>> c));<br>
> >>>> >> + bld.ADD(offset(addr, bld, c),<br>
> >>>> >> + offset(addr, bld, c), offset(tmp, bld, c));<br>
> >>>> >> + }<br>
> >>>> >> + }<br>
> >>>> >> +<br>
> >>>> >> + if (dims > 1) {<br>
> >>>> ><br>
> >>>> > Please add as a comment:<br>
> >>>> > /*<br>
> >>>> > Calculate the major/minor x and y indices. In order to accommodate<br>
> >>>> > both X and Y tiling, the Y-major tiling format is treated as being a<br>
> >>>> > bunch of narrow X-tiles placed next to each other. This means that<br>
> >>>> > the tile width for Y-tiling is actually the width of one sub-column of<br>
> >>>> > the Y-major tile where each 4K tile has 8 512B sub-columns.<br>
> >>>> ><br>
> >>>> > The major Y value is the row of tiles in which the pixel lives. The<br>
> >>>> > major X value is the tile sub-column in which the pixel lives; for X<br>
> >>>> > tiling, this is the same as the tile column, for Y tiling, each tile<br>
> >>>> > has 8 sub-columns. The minor X and Y indices are the position within<br>
> >>>> > the sub-column.<br>
> >>>> > */<br>
> >>>> >> + for (unsigned c = 0; c < 2; ++c) {<br>
> >>>> >> + /* Calculate the minor x and y indices. */<br>
> >>>> >> + bld.BFE(offset(minor, bld, c), offset(tile, bld, c),<br>
> >>>> >> + fs_reg(0), offset(addr, bld, c));<br>
> >>>> >> +<br>
> >>>> >> + /* Calculate the major x and y indices. */<br>
> >>>> >> + bld.SHR(offset(major, bld, c),<br>
> >>>> >> + offset(addr, bld, c), offset(tile, bld, c));<br>
> >>>> >> + }<br>
> >>>> >> +<br>
> >>>> >> + /* Calculate the texel index from the start of the tile<br>
> >>> row and<br>
> >>>> >> + * the vertical coordinate of the row.<br>
> >>>> >> + * Equivalent to:<br>
> >>>> >> + * tmp.x = (major.x << tile.y << tile.x) +<br>
> >>>> >> + * (minor.y << tile.x) + minor.x<br>
> >>>> >> + * tmp.y = major.y << tile.y<br>
> >>>> >> + */<br>
> >>>> >> + bld.SHL(tmp, major, offset(tile, bld, 1));<br>
> >>>> >> + bld.ADD(tmp, tmp, offset(minor, bld, 1));<br>
> >>>> >> + bld.SHL(tmp, tmp, offset(tile, bld, 0));<br>
> >>>> >> + bld.ADD(tmp, tmp, minor);<br>
> >>>> >> + bld.SHL(offset(tmp, bld, 1),<br>
> >>>> >> + offset(major, bld, 1), offset(tile, bld, 1));<br>
> >>>> >> +<br>
> >>>> >> + /* Add it to the start of the tile row. */<br>
> >>>> >> + bld.MUL(offset(tmp, bld, 1),<br>
> >>>> >> + offset(tmp, bld, 1), offset(stride, bld, 1));<br>
> >>>> >> + bld.ADD(tmp, tmp, offset(tmp, bld, 1));<br>
> >>>> >> +<br>
> >>>> >> + /* Multiply by the Bpp value. */<br>
> >>>> >> + bld.MUL(dst, tmp, stride);<br>
> >>>> >> +<br>
> >>>> >> + if (devinfo->gen < 8 && !devinfo->is_baytrail) {<br>
> >>>> ><br>
> >>>> > Talking to Ken a bit about this. It seems as if this is actually the<br>
> >>>> > check we want. It's going to be a nasty bug if someone has a shader<br>
> >>>> > cache on a HSW machine, runs some compute shaders, pulls out a stick<br>
> >>>> > of ram (going from dual to single-channel), and starts it up again.<br>
> >>>> > Probably best to compile the shader the same regardless of how much<br>
> >>>> > ram you have.<br>
> >>>> ><br>
> >>>> Hmm, I guess we could also invalidate the cache if the flag changes?<br>
> >>>> (or in case anything else changes from the brw_device_info structure)<br>
> >>>><br>
> >>>> >> + /* Take into account the two dynamically specified<br>
> >>> shifts. */<br>
> >>>> >> + for (unsigned c = 0; c < 2; ++c)<br>
> >>>> >> + bld.SHR(offset(tmp, bld, c), dst, offset(swz, bld,<br>
> >>> c));<br>
> >>>> >> +<br>
> >>>> >> + /* XOR tmp.x and tmp.y with bit 6 of the memory<br>
> >>> address. */<br>
> >>>> >> + bld.XOR(tmp, tmp, offset(tmp, bld, 1));<br>
> >>>> >> + bld.AND(tmp, tmp, fs_reg(1 << 6));<br>
> >>>> >> + bld.XOR(dst, dst, tmp);<br>
> >>>> ><br>
> >>>> > I don't think this is correct for Y-tiled surfaces. In Y-tiling, bit<br>
> >>>> > 6 of the address is given by bit6 XOR bit9. You have one extra XOR<br>
> >>>> > which means you just get just bit9.<br>
> >>>> ><br>
> >>>> The extra XOR is made a no-op for the Y-tiled case in the same way that<br>
> >>>> they are both made a no-op in the no-swizzling case. I'll add another<br>
> >>>> comment clarifying that.<br>
> >>><br>
> >>> I don't think that actually works. In the zero-shift case, the first XOR<br>
> >>> produces an all-zero value, you mask to bit 6 (still all-zero) and XOR with<br>
> >>> the original value and get the original back. In the Y-tiled case, you<br>
> >>> compute a ^ (a >> 3) and mask off bit 6. This gives you bit6 ^ bit9 in the<br>
> >>> sixth bit and zero everywhere else. When you then XOR that with the<br>
> >>> original, the two copies of bit6 cancel out and you are left with bit9 only.<br>
> >>><br>
> >> Not exactly, in either case the result of the swizzling calculation<br>
> >> is:<br>
> >> addr' = addr ^ ((1 << 6) & ((addr >> swz.x) ^ (addr >> swz.y)))<br>
> >><br>
> >> If the surface is Y-tiled, swz.x = 3 and swz.y = 31, which gives:<br>
> >> addr' = addr ^ ((1 << 6) & ((addr[9] ^ addr[37]) << 6)) =<br>
> >> addr ^ ((addr[9] ^ 0) << 6) = addr ^ (addr[9] << 6)<br>
> >><br>
> >> I guess I should add another comment here about how the XOR instructions<br>
> >> are NOP-ed out when they're not needed. :)<br>
> ><br>
> > Right. I'd missed the fact that the default swizzle was not zero.<br>
> > Also, it's 0xff, so it's 255, not 31. I'm not sure what addr >> 255<br>
> > does. Maybe it only takes 5 bits and it's actually 31, but we should<br>
> > probably use 31 rather than 255.<br>
><br>
> Yeah, I wrote 31 because the actual value used by the hardware is the<br>
> LSBs of the shift value depending on the execution type -- I.e. 5 bits<br>
> for UD. We could definitely initialize the swz parameters to 0x1f as<br>
> well but I used 0xff instead because it would also work for larger<br>
> offset types, e.g. 64bit in which case the hardware shift instruction<br>
> would take the lowest 6 bits -- I'm not planning to extend the code<br>
> above to handle 64-bit offsets anytime soon though.</p>
<p dir="ltr">I don't care too much which we use. However, there should be comments both here and where we set the defaults saying why the defeault is 31/0xff.</p>
<p dir="ltr">> > --Jason<br>
> ><br>
> >>>> >> + }<br>
> >>>> >> +<br>
> >>>> >> + } else {<br>
> >>>> >> + /* Multiply by the Bpp/stride value. */<br>
> >>>> ><br>
> >>>> > I'm still confused as to how addr can have 2 things while dims == 1.<br>
> >>>> > Does dims specify the per-slice dimension or total dimension? That<br>
> >>>> > should probably be documented at the top of the function.<br>
> >>>> ><br>
> >>>> dims specifies the dimension of the coord argument. addr may still have<br>
> >>>> a non-zero y coordinate because it's the sum of coord and the<br>
> >>>> two-dimensional offset value specified by surface set-up. 1D texture<br>
> >>>> slices and levels are laid out in a 2D layout just like the rest, the<br>
> >>>> offset value specifies where in the 2D miptree the requested 1D image<br>
> >>>> starts. You may wonder why we pass a 2D offset to the shader instead of<br>
> >>>> just fixing up the surface base memory address to point at the right<br>
> >>>> slice at offset (0, 0), the answer is that in the general case (i.e. not<br>
> >>>> necessarily 1D) it wouldn't work, because a level may start mid-tile and<br>
> >>>> the result of shifting a tiled surface by less than the tile size is in<br>
> >>>> general not a well-formed tiled surface -- In the 1D case it could<br>
> >>>> probably be done though because I deliberately disabled tiling for those<br>
> >>>> (36a17f0f9913), but it would require special-casing them in the surface<br>
> >>>> state set-up code and another manual calculation of the base memory<br>
> >>>> address of the right slice-level of the miptree.<br>
> >>>><br>
> >>>> >> + bld.MUL(offset(addr, bld, 1),<br>
> >>>> >> + offset(addr, bld, 1), offset(stride, bld, 1));<br>
> >>>> >> + bld.ADD(addr, addr, offset(addr, bld, 1));<br>
> >>>> >> + bld.MUL(dst, addr, stride);<br>
> >>>> >> + }<br>
> >>>> >> +<br>
> >>>> >> + return dst;<br>
> >>>> >> + }<br>
> >>>> >> + }<br>
> >>>> >> }<br>
> >>>> >> --<br>
> >>>> >> 2.4.3<br>
> >>>> >><br>
> >>>> >> _______________________________________________<br>
> >>>> >> mesa-dev mailing list<br>
> >>>> >> <a href="mailto:mesa-dev@lists.freedesktop.org">mesa-dev@lists.freedesktop.org</a><br>
> >>>> >> <a href="http://lists.freedesktop.org/mailman/listinfo/mesa-dev">http://lists.freedesktop.org/mailman/listinfo/mesa-dev</a><br>
</p>