gallivm: handle cube map arrays for texture sampling
authorRoland Scheidegger <sroland@vmware.com>
Fri, 29 Aug 2014 23:32:59 +0000 (01:32 +0200)
committerRoland Scheidegger <sroland@vmware.com>
Fri, 29 Aug 2014 23:33:02 +0000 (01:33 +0200)
Pretty easy, just make sure that all paths testing for PIPE_TEXTURE_CUBE
also recognize PIPE_TEXTURE_CUBE_ARRAY, and add the layer * 6 calculation
to the calculated face.
Also handle it for texture size query, looks like OpenGL wants the number
of cubes, not layers (so need division by 6).

No piglit regressions.

v2: fix up adding cube layer to face for seamless filtering (needs to happen
after calculating per-sample face). Undetected by piglit unfortunately.

Reviewed-by: Jose Fonseca <jfonseca@vmware.com> (v1)
src/gallium/auxiliary/gallivm/lp_bld_sample.c
src/gallium/auxiliary/gallivm/lp_bld_sample.h
src/gallium/auxiliary/gallivm/lp_bld_sample_aos.c
src/gallium/auxiliary/gallivm/lp_bld_sample_soa.c
src/gallium/auxiliary/gallivm/lp_bld_tgsi_soa.c

index f1bf28519debdbdd823df7a67425304966071292..85c0d4ed6f8d4319f1f8f300fc4cd44b002c88d1 100644 (file)
@@ -1313,10 +1313,7 @@ lp_build_mipmap_level_sizes(struct lp_build_sample_context *bld,
                                                       bld->row_stride_array,
                                                       ilevel);
    }
-   if (dims == 3 ||
-       bld->static_texture_state->target == PIPE_TEXTURE_CUBE ||
-       bld->static_texture_state->target == PIPE_TEXTURE_1D_ARRAY ||
-       bld->static_texture_state->target == PIPE_TEXTURE_2D_ARRAY) {
+   if (dims == 3 || has_layer_coord(bld->static_texture_state->target)) {
       *img_stride_vec = lp_build_get_level_stride_vec(bld,
                                                       bld->img_stride_array,
                                                       ilevel);
index fd4e0532607dbfef0ab82d73b1a35a8a303e8d9d..be05b136edbe564be2588eab750f506a808839bd 100644 (file)
@@ -356,9 +356,7 @@ texture_dims(enum pipe_texture_target tex)
    case PIPE_TEXTURE_2D_ARRAY:
    case PIPE_TEXTURE_RECT:
    case PIPE_TEXTURE_CUBE:
-      return 2;
    case PIPE_TEXTURE_CUBE_ARRAY:
-      assert(0);
       return 2;
    case PIPE_TEXTURE_3D:
       return 3;
@@ -368,6 +366,21 @@ texture_dims(enum pipe_texture_target tex)
    }
 }
 
+static INLINE boolean
+has_layer_coord(enum pipe_texture_target tex)
+{
+   switch (tex) {
+   case PIPE_TEXTURE_1D_ARRAY:
+   case PIPE_TEXTURE_2D_ARRAY:
+   /* cube is not layered but 3rd coord (after cube mapping) behaves the same */
+   case PIPE_TEXTURE_CUBE:
+   case PIPE_TEXTURE_CUBE_ARRAY:
+      return TRUE;
+   default:
+      return FALSE;
+   }
+}
+
 
 boolean
 lp_sampler_wrap_mode_uses_border_color(unsigned mode,
index 2f026065766675b96178c7f2e9365b9baafd4f39..394521d382a8acfc9cb6f5494948c5781eea4477 100644 (file)
@@ -704,9 +704,7 @@ lp_build_sample_image_nearest(struct lp_build_sample_context *bld,
          offset = lp_build_add(&bld->int_coord_bld, offset, z_offset);
       }
    }
-   if (bld->static_texture_state->target == PIPE_TEXTURE_CUBE ||
-       bld->static_texture_state->target == PIPE_TEXTURE_1D_ARRAY ||
-       bld->static_texture_state->target == PIPE_TEXTURE_2D_ARRAY) {
+   if (has_layer_coord(bld->static_texture_state->target)) {
       LLVMValueRef z_offset;
       /* The r coord is the cube face in [0,5] or array layer */
       z_offset = lp_build_mul(&bld->int_coord_bld, r, img_stride_vec);
@@ -781,9 +779,7 @@ lp_build_sample_image_nearest_afloat(struct lp_build_sample_context *bld,
                                             &z_icoord);
       }
    }
-   if (bld->static_texture_state->target == PIPE_TEXTURE_CUBE ||
-       bld->static_texture_state->target == PIPE_TEXTURE_1D_ARRAY ||
-       bld->static_texture_state->target == PIPE_TEXTURE_2D_ARRAY) {
+   if (has_layer_coord(bld->static_texture_state->target)) {
       z_icoord = r;
    }
 
@@ -1130,9 +1126,7 @@ lp_build_sample_image_linear(struct lp_build_sample_context *bld,
                                    &x_subcoord[0], &x_subcoord[1]);
 
    /* add potential cube/array/mip offsets now as they are constant per pixel */
-   if (bld->static_texture_state->target == PIPE_TEXTURE_CUBE ||
-       bld->static_texture_state->target == PIPE_TEXTURE_1D_ARRAY ||
-       bld->static_texture_state->target == PIPE_TEXTURE_2D_ARRAY) {
+   if (has_layer_coord(bld->static_texture_state->target)) {
       LLVMValueRef z_offset;
       z_offset = lp_build_mul(&bld->int_coord_bld, r, img_stride_vec);
       /* The r coord is the cube face in [0,5] or array layer */
@@ -1301,9 +1295,7 @@ lp_build_sample_image_linear_afloat(struct lp_build_sample_context *bld,
                                   &x_offset1, &x_subcoord[1]);
 
    /* add potential cube/array/mip offsets now as they are constant per pixel */
-   if (bld->static_texture_state->target == PIPE_TEXTURE_CUBE ||
-       bld->static_texture_state->target == PIPE_TEXTURE_1D_ARRAY ||
-       bld->static_texture_state->target == PIPE_TEXTURE_2D_ARRAY) {
+   if (has_layer_coord(bld->static_texture_state->target)) {
       LLVMValueRef z_offset;
       z_offset = lp_build_mul(&bld->int_coord_bld, r, img_stride_vec);
       /* The r coord is the cube face in [0,5] or array layer */
index e29f5034452aced63b9fd6c01aece29857131624..99309fe75bda7a5691b7f79353524daa38820422 100644 (file)
@@ -752,10 +752,14 @@ lp_build_sample_image_nearest(struct lp_build_sample_context *bld,
          lp_build_name(z, "tex.z.wrapped");
       }
    }
-   if (bld->static_texture_state->target == PIPE_TEXTURE_CUBE ||
-       bld->static_texture_state->target == PIPE_TEXTURE_1D_ARRAY ||
-       bld->static_texture_state->target == PIPE_TEXTURE_2D_ARRAY) {
-      z = coords[2];
+   if (has_layer_coord(bld->static_texture_state->target)) {
+      if (bld->static_texture_state->target == PIPE_TEXTURE_CUBE_ARRAY) {
+         /* add cube layer to face */
+         z = lp_build_add(&bld->int_coord_bld, coords[2], coords[3]);
+      }
+      else {
+         z = coords[2];
+      }
       lp_build_name(z, "tex.z.layer");
    }
 
@@ -868,7 +872,8 @@ lp_build_sample_image_linear(struct lp_build_sample_context *bld,
    int chan, texel_index;
    boolean seamless_cube_filter, accurate_cube_corners;
 
-   seamless_cube_filter = bld->static_texture_state->target == PIPE_TEXTURE_CUBE &&
+   seamless_cube_filter = (bld->static_texture_state->target == PIPE_TEXTURE_CUBE ||
+                           bld->static_texture_state->target == PIPE_TEXTURE_CUBE_ARRAY) &&
                           bld->static_sampler_state->seamless_cube_map;
    accurate_cube_corners = ACCURATE_CUBE_CORNERS && seamless_cube_filter;
 
@@ -923,10 +928,15 @@ lp_build_sample_image_linear(struct lp_build_sample_context *bld,
             lp_build_name(z1, "tex.z1.wrapped");
          }
       }
-      if (bld->static_texture_state->target == PIPE_TEXTURE_CUBE ||
-          bld->static_texture_state->target == PIPE_TEXTURE_1D_ARRAY ||
-          bld->static_texture_state->target == PIPE_TEXTURE_2D_ARRAY) {
-         z00 = z01 = z10 = z11 = z1 = coords[2];  /* cube face or layer */
+      if (has_layer_coord(bld->static_texture_state->target)) {
+         if (bld->static_texture_state->target == PIPE_TEXTURE_CUBE_ARRAY) {
+            /* add cube layer to face */
+            z00 = z01 = z10 = z11 = z1 =
+               lp_build_add(&bld->int_coord_bld, coords[2], coords[3]);
+         }
+         else {
+            z00 = z01 = z10 = z11 = z1 = coords[2];  /* cube face or layer */
+         }
          lp_build_name(z00, "tex.z0.layer");
          lp_build_name(z1, "tex.z1.layer");
       }
@@ -1047,6 +1057,14 @@ lp_build_sample_image_linear(struct lp_build_sample_context *bld,
       z10 = lp_build_select(ivec_bld, fall_off_yp_notxm, new_faces[3], z10);
       z11 = lp_build_select(ivec_bld, fall_off_yp_notxp, new_faces[3], z11);
 
+      if (bld->static_texture_state->target == PIPE_TEXTURE_CUBE_ARRAY) {
+         /* now can add cube layer to face (per sample) */
+         z00 = lp_build_add(ivec_bld, z00, coords[3]);
+         z01 = lp_build_add(ivec_bld, z01, coords[3]);
+         z10 = lp_build_add(ivec_bld, z10, coords[3]);
+         z11 = lp_build_add(ivec_bld, z11, coords[3]);
+      }
+
       LLVMBuildStore(builder, x00, xs[0]);
       LLVMBuildStore(builder, x01, xs[1]);
       LLVMBuildStore(builder, x10, xs[2]);
@@ -1070,10 +1088,19 @@ lp_build_sample_image_linear(struct lp_build_sample_context *bld,
       LLVMBuildStore(builder, y0, ys[1]);
       LLVMBuildStore(builder, y1, ys[2]);
       LLVMBuildStore(builder, y1, ys[3]);
-      LLVMBuildStore(builder, face, zs[0]);
-      LLVMBuildStore(builder, face, zs[1]);
-      LLVMBuildStore(builder, face, zs[2]);
-      LLVMBuildStore(builder, face, zs[3]);
+      if (bld->static_texture_state->target == PIPE_TEXTURE_CUBE_ARRAY) {
+         LLVMValueRef cube_layer = lp_build_add(ivec_bld, face, coords[3]);
+         LLVMBuildStore(builder, cube_layer, zs[0]);
+         LLVMBuildStore(builder, cube_layer, zs[1]);
+         LLVMBuildStore(builder, cube_layer, zs[2]);
+         LLVMBuildStore(builder, cube_layer, zs[3]);
+      }
+      else {
+         LLVMBuildStore(builder, face, zs[0]);
+         LLVMBuildStore(builder, face, zs[1]);
+         LLVMBuildStore(builder, face, zs[2]);
+         LLVMBuildStore(builder, face, zs[3]);
+      }
 
       lp_build_endif(&edge_if);
 
@@ -1644,6 +1671,7 @@ lp_build_sample_mipmap_both(struct lp_build_sample_context *bld,
 static LLVMValueRef
 lp_build_layer_coord(struct lp_build_sample_context *bld,
                      unsigned texture_unit,
+                     boolean is_cube_array,
                      LLVMValueRef layer,
                      LLVMValueRef *out_of_bounds)
 {
@@ -1655,6 +1683,7 @@ lp_build_layer_coord(struct lp_build_sample_context *bld,
 
    if (out_of_bounds) {
       LLVMValueRef out1, out;
+      assert(!is_cube_array);
       num_layers = lp_build_broadcast_scalar(int_coord_bld, num_layers);
       out = lp_build_cmp(int_coord_bld, PIPE_FUNC_LESS, layer, int_coord_bld->zero);
       out1 = lp_build_cmp(int_coord_bld, PIPE_FUNC_GEQUAL, layer, num_layers);
@@ -1663,7 +1692,9 @@ lp_build_layer_coord(struct lp_build_sample_context *bld,
    }
    else {
       LLVMValueRef maxlayer;
-      maxlayer = lp_build_sub(&bld->int_bld, num_layers, bld->int_bld.one);
+      LLVMValueRef s = is_cube_array ? lp_build_const_int32(bld->gallivm, 6) :
+                                       bld->int_bld.one;
+      maxlayer = lp_build_sub(&bld->int_bld, num_layers, s);
       maxlayer = lp_build_broadcast_scalar(int_coord_bld, maxlayer);
       return lp_build_clamp(int_coord_bld, layer, int_coord_bld->zero, maxlayer);
    }
@@ -1703,7 +1734,7 @@ lp_build_sample_common(struct lp_build_sample_context *bld,
     * Choose cube face, recompute texcoords for the chosen face and
     * compute rho here too (as it requires transform of derivatives).
     */
-   if (target == PIPE_TEXTURE_CUBE) {
+   if (target == PIPE_TEXTURE_CUBE || target == PIPE_TEXTURE_CUBE_ARRAY) {
       boolean need_derivs;
       need_derivs = ((min_filter != mag_filter ||
                       mip_filter != PIPE_TEX_MIPFILTER_NONE) &&
@@ -1711,11 +1742,19 @@ lp_build_sample_common(struct lp_build_sample_context *bld,
                       !explicit_lod);
       lp_build_cube_lookup(bld, coords, derivs, &cube_rho, &cube_derivs, need_derivs);
       derivs = &cube_derivs;
+      if (target == PIPE_TEXTURE_CUBE_ARRAY) {
+         /* calculate cube layer coord now */
+         LLVMValueRef layer = lp_build_iround(&bld->coord_bld, coords[3]);
+         LLVMValueRef six = lp_build_const_int_vec(bld->gallivm, bld->int_coord_type, 6);
+         layer = lp_build_mul(&bld->int_coord_bld, layer, six);
+         coords[3] = lp_build_layer_coord(bld, texture_index, TRUE, layer, NULL);
+         /* because of seamless filtering can't add it to face (coords[2]) here. */
+      }
    }
    else if (target == PIPE_TEXTURE_1D_ARRAY ||
             target == PIPE_TEXTURE_2D_ARRAY) {
       coords[2] = lp_build_iround(&bld->coord_bld, coords[2]);
-      coords[2] = lp_build_layer_coord(bld, texture_index, coords[2], NULL);
+      coords[2] = lp_build_layer_coord(bld, texture_index, FALSE, coords[2], NULL);
    }
 
    if (bld->static_sampler_state->compare_mode != PIPE_TEX_COMPARE_NONE) {
@@ -2223,11 +2262,11 @@ lp_build_fetch_texel(struct lp_build_sample_context *bld,
    if (target == PIPE_TEXTURE_1D_ARRAY ||
        target == PIPE_TEXTURE_2D_ARRAY) {
       if (out_of_bound_ret_zero) {
-         z = lp_build_layer_coord(bld, texture_unit, z, &out1);
+         z = lp_build_layer_coord(bld, texture_unit, FALSE, z, &out1);
          out_of_bounds = lp_build_or(int_coord_bld, out_of_bounds, out1);
       }
       else {
-         z = lp_build_layer_coord(bld, texture_unit, z, NULL);
+         z = lp_build_layer_coord(bld, texture_unit, FALSE, z, NULL);
       }
    }
 
@@ -2463,7 +2502,8 @@ lp_build_sample_soa(struct gallivm_state *gallivm,
 
    if ((gallivm_debug & GALLIVM_DEBUG_NO_QUAD_LOD) &&
        (gallivm_debug & GALLIVM_DEBUG_NO_RHO_APPROX) &&
-       (static_texture_state->target == PIPE_TEXTURE_CUBE) &&
+       (static_texture_state->target == PIPE_TEXTURE_CUBE ||
+        static_texture_state->target == PIPE_TEXTURE_CUBE_ARRAY) &&
        (!is_fetch && mip_filter != PIPE_TEX_MIPFILTER_NONE)) {
       /*
        * special case for using per-pixel lod even for implicit lod,
@@ -2601,7 +2641,8 @@ lp_build_sample_soa(struct gallivm_state *gallivm,
             use_aos &= lp_is_simple_wrap_mode(derived_sampler_state.wrap_r);
          }
       }
-      if (static_texture_state->target == PIPE_TEXTURE_CUBE &&
+      if ((static_texture_state->target == PIPE_TEXTURE_CUBE ||
+           static_texture_state->target == PIPE_TEXTURE_CUBE_ARRAY) &&
           derived_sampler_state.seamless_cube_map &&
           (derived_sampler_state.min_img_filter == PIPE_TEX_FILTER_LINEAR ||
            derived_sampler_state.mag_img_filter == PIPE_TEX_FILTER_LINEAR)) {
@@ -2631,6 +2672,13 @@ lp_build_sample_soa(struct gallivm_state *gallivm,
                              &lod_positive, &lod_fpart,
                              &ilevel0, &ilevel1);
 
+      if (use_aos && static_texture_state->target == PIPE_TEXTURE_CUBE_ARRAY) {
+         /* The aos path doesn't do seamless filtering so simply add cube layer
+          * to face now.
+          */
+         newcoords[2] = lp_build_add(&bld.int_coord_bld, newcoords[2], newcoords[3]);
+      }
+
       /*
        * we only try 8-wide sampling with soa as it appears to
        * be a loss with aos with AVX (but it should work, except
@@ -2695,7 +2743,8 @@ lp_build_sample_soa(struct gallivm_state *gallivm,
          bld4.num_mips = bld4.num_lods = 1;
          if ((gallivm_debug & GALLIVM_DEBUG_NO_QUAD_LOD) &&
              (gallivm_debug & GALLIVM_DEBUG_NO_RHO_APPROX) &&
-             (static_texture_state->target == PIPE_TEXTURE_CUBE) &&
+             (static_texture_state->target == PIPE_TEXTURE_CUBE ||
+              static_texture_state->target == PIPE_TEXTURE_CUBE_ARRAY) &&
              (!is_fetch && mip_filter != PIPE_TEX_MIPFILTER_NONE)) {
             bld4.num_mips = type4.length;
             bld4.num_lods = type4.length;
@@ -2891,6 +2940,7 @@ lp_build_size_query_soa(struct gallivm_state *gallivm,
    switch (target) {
    case PIPE_TEXTURE_1D_ARRAY:
    case PIPE_TEXTURE_2D_ARRAY:
+   case PIPE_TEXTURE_CUBE_ARRAY:
       has_array = TRUE;
       break;
    default:
@@ -2932,10 +2982,20 @@ lp_build_size_query_soa(struct gallivm_state *gallivm,
 
    size = lp_build_minify(&bld_int_vec4, size, lod, TRUE);
 
-   if (has_array)
-      size = LLVMBuildInsertElement(gallivm->builder, size,
-                                    dynamic_state->depth(dynamic_state, gallivm, texture_unit),
+   if (has_array) {
+      LLVMValueRef layers = dynamic_state->depth(dynamic_state, gallivm, texture_unit);
+      if (target == PIPE_TEXTURE_CUBE_ARRAY) {
+         /*
+          * It looks like GL wants number of cubes, d3d10.1 has it undefined?
+          * Could avoid this by passing in number of cubes instead of total
+          * number of layers (might make things easier elsewhere too).
+          */
+         LLVMValueRef six = lp_build_const_int32(gallivm, 6);
+         layers = LLVMBuildSDiv(gallivm->builder, layers, six, "");
+      }
+      size = LLVMBuildInsertElement(gallivm->builder, size, layers,
                                     lp_build_const_int32(gallivm, dims), "");
+   }
 
    /*
     * d3d10 requires zero for x/y/z values (but not w, i.e. mip levels)
index 93c926ade9420d78070e70a55e50bc5d1eeeae2f..c0bd7bec1936bab6b597792772772f020fefd7d1 100644 (file)
@@ -2333,7 +2333,7 @@ emit_fetch_texels( struct lp_build_tgsi_soa_context *bld,
    unsigned unit, target;
    LLVMValueRef coord_undef = LLVMGetUndef(bld->bld_base.base.int_vec_type);
    LLVMValueRef explicit_lod = NULL;
-   LLVMValueRef coords[3];
+   LLVMValueRef coords[5];
    LLVMValueRef offsets[3] = { NULL };
    enum lp_sampler_lod_property lod_property = LP_SAMPLER_LOD_SCALAR;
    unsigned dims, i;
@@ -2395,7 +2395,8 @@ emit_fetch_texels( struct lp_build_tgsi_soa_context *bld,
    for (i = 0; i < dims; i++) {
       coords[i] = lp_build_emit_fetch(&bld->bld_base, inst, 0, i);
    }
-   for (i = dims; i < 3; i++) {
+   /* never use more than 3 coords here but emit_fetch_texel copies all 5 anyway */
+   for (i = dims; i < 5; i++) {
       coords[i] = coord_undef;
    }
    if (layer_coord)