Home | History | Annotate | Download | only in core
      1 /*
      2  * Mesa 3-D graphics library
      3  *
      4  * Copyright (C) 2012-2015 LunarG, Inc.
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a
      7  * copy of this software and associated documentation files (the "Software"),
      8  * to deal in the Software without restriction, including without limitation
      9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     10  * and/or sell copies of the Software, and to permit persons to whom the
     11  * Software is furnished to do so, subject to the following conditions:
     12  *
     13  * The above copyright notice and this permission notice shall be included
     14  * in all copies or substantial portions of the Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
     22  * DEALINGS IN THE SOFTWARE.
     23  *
     24  * Authors:
     25  *    Chia-I Wu <olv (at) lunarg.com>
     26  */
     27 
     28 #include "ilo_debug.h"
     29 #include "ilo_state_viewport.h"
     30 
     31 static void
     32 viewport_matrix_get_gen6_guardband(const struct ilo_dev *dev,
     33                                    const struct ilo_state_viewport_matrix_info *mat,
     34                                    float *min_gbx, float *max_gbx,
     35                                    float *min_gby, float *max_gby)
     36 {
     37    /*
     38     * From the Sandy Bridge PRM, volume 2 part 1, page 234:
     39     *
     40     *     "Per-Device Guardband Extents
     41     *
     42     *       - Supported X,Y ScreenSpace "Guardband" Extent: [-16K,16K-1]
     43     *       - Maximum Post-Clamp Delta (X or Y): 16K"
     44     *
     45     *     "In addition, in order to be correctly rendered, objects must have a
     46     *      screenspace bounding box not exceeding 8K in the X or Y direction.
     47     *      This additional restriction must also be comprehended by software,
     48     *      i.e., enforced by use of clipping."
     49     *
     50     * From the Ivy Bridge PRM, volume 2 part 1, page 248:
     51     *
     52     *     "Per-Device Guardband Extents
     53     *
     54     *       - Supported X,Y ScreenSpace "Guardband" Extent: [-32K,32K-1]
     55     *       - Maximum Post-Clamp Delta (X or Y): N/A"
     56     *
     57     *     "In addition, in order to be correctly rendered, objects must have a
     58     *      screenspace bounding box not exceeding 8K in the X or Y direction.
     59     *      This additional restriction must also be comprehended by software,
     60     *      i.e., enforced by use of clipping."
     61     *
     62     * Combined, the bounding box of any object can not exceed 8K in both
     63     * width and height.
     64     *
     65     * Below we set the guardband as a squre of length 8K, centered at where
     66     * the viewport is.  This makes sure all objects passing the GB test are
     67     * valid to the renderer, and those failing the XY clipping have a
     68     * better chance of passing the GB test.
     69     */
     70    const int max_extent = (ilo_dev_gen(dev) >= ILO_GEN(7)) ? 32768 : 16384;
     71    const int half_len = 8192 / 2;
     72    int center_x = (int) mat->translate[0];
     73    int center_y = (int) mat->translate[1];
     74    float scale_x, scale_y;
     75 
     76    ILO_DEV_ASSERT(dev, 6, 8);
     77 
     78    /* make sure the guardband is within the valid range */
     79    if (center_x - half_len < -max_extent)
     80       center_x = -max_extent + half_len;
     81    else if (center_x + half_len > max_extent - 1)
     82       center_x = max_extent - half_len;
     83 
     84    if (center_y - half_len < -max_extent)
     85       center_y = -max_extent + half_len;
     86    else if (center_y + half_len > max_extent - 1)
     87       center_y = max_extent - half_len;
     88 
     89    scale_x = fabsf(mat->scale[0]);
     90    scale_y = fabsf(mat->scale[1]);
     91    /*
     92     * From the Haswell PRM, volume 2d, page 292-293:
     93     *
     94     *     "Note: Minimum allowed value for this field (X/Y Min Clip Guardband)
     95     *      is -16384."
     96     *
     97     *     "Note: Maximum allowed value for this field (X/Y Max Clip Guardband)
     98     *      is 16383."
     99     *
    100     * Avoid small scales.
    101     */
    102    if (scale_x < 1.0f)
    103       scale_x = 1.0f;
    104    if (scale_y < 1.0f)
    105       scale_y = 1.0f;
    106 
    107    /* in NDC space */
    108    *min_gbx = ((float) (center_x - half_len) - mat->translate[0]) / scale_x;
    109    *max_gbx = ((float) (center_x + half_len) - mat->translate[0]) / scale_x;
    110    *min_gby = ((float) (center_y - half_len) - mat->translate[1]) / scale_y;
    111    *max_gby = ((float) (center_y + half_len) - mat->translate[1]) / scale_y;
    112 }
    113 
    114 static void
    115 viewport_matrix_get_extent(const struct ilo_state_viewport_matrix_info *mat,
    116                            int axis, float *min, float *max)
    117 {
    118    const float scale_abs = fabsf(mat->scale[axis]);
    119 
    120    *min = -1.0f * scale_abs + mat->translate[axis];
    121    *max =  1.0f * scale_abs + mat->translate[axis];
    122 }
    123 
    124 static bool
    125 viewport_matrix_set_gen7_SF_CLIP_VIEWPORT(struct ilo_state_viewport *vp,
    126                                           const struct ilo_dev *dev,
    127                                           const struct ilo_state_viewport_matrix_info *matrices,
    128                                           uint8_t count)
    129 {
    130    uint8_t i;
    131 
    132    ILO_DEV_ASSERT(dev, 6, 8);
    133 
    134    for (i = 0; i < count; i++) {
    135       const struct ilo_state_viewport_matrix_info *mat = &matrices[i];
    136       float min_gbx, max_gbx, min_gby, max_gby;
    137       uint32_t dw[16];
    138 
    139       viewport_matrix_get_gen6_guardband(dev, mat,
    140             &min_gbx, &max_gbx, &min_gby, &max_gby);
    141 
    142       dw[0] = fui(mat->scale[0]);
    143       dw[1] = fui(mat->scale[1]);
    144       dw[2] = fui(mat->scale[2]);
    145       dw[3] = fui(mat->translate[0]);
    146       dw[4] = fui(mat->translate[1]);
    147       dw[5] = fui(mat->translate[2]);
    148       dw[6] = 0;
    149       dw[7] = 0;
    150 
    151       dw[8] = fui(min_gbx);
    152       dw[9] = fui(max_gbx);
    153       dw[10] = fui(min_gby);
    154       dw[11] = fui(max_gby);
    155 
    156       if (ilo_dev_gen(dev) >= ILO_GEN(8)) {
    157          float min_x, max_x, min_y, max_y;
    158 
    159          viewport_matrix_get_extent(mat, 0, &min_x, &max_x);
    160          viewport_matrix_get_extent(mat, 1, &min_y, &max_y);
    161 
    162          dw[12] = fui(min_x);
    163          dw[13] = fui(max_x - 1.0f);
    164          dw[14] = fui(min_y);
    165          dw[15] = fui(max_y - 1.0f);
    166       } else {
    167          dw[12] = 0;
    168          dw[13] = 0;
    169          dw[14] = 0;
    170          dw[15] = 0;
    171       }
    172 
    173       STATIC_ASSERT(ARRAY_SIZE(vp->sf_clip[i]) >= 16);
    174       memcpy(vp->sf_clip[i], dw, sizeof(dw));
    175    }
    176 
    177    return true;
    178 }
    179 
    180 static bool
    181 viewport_matrix_set_gen6_CC_VIEWPORT(struct ilo_state_viewport *vp,
    182                                      const struct ilo_dev *dev,
    183                                      const struct ilo_state_viewport_matrix_info *matrices,
    184                                      uint8_t count)
    185 {
    186    uint8_t i;
    187 
    188    ILO_DEV_ASSERT(dev, 6, 8);
    189 
    190    for (i = 0; i < count; i++) {
    191       const struct ilo_state_viewport_matrix_info *mat = &matrices[i];
    192       float min_z, max_z;
    193 
    194       viewport_matrix_get_extent(mat, 2, &min_z, &max_z);
    195 
    196       STATIC_ASSERT(ARRAY_SIZE(vp->cc[i]) >= 2);
    197       vp->cc[i][0] = fui(min_z);
    198       vp->cc[i][1] = fui(max_z);
    199    }
    200 
    201    return true;
    202 }
    203 
    204 static bool
    205 viewport_scissor_set_gen6_SCISSOR_RECT(struct ilo_state_viewport *vp,
    206                                        const struct ilo_dev *dev,
    207                                        const struct ilo_state_viewport_scissor_info *scissors,
    208                                        uint8_t count)
    209 {
    210    const uint16_t max_size = (ilo_dev_gen(dev) >= ILO_GEN(7)) ? 16384 : 8192;
    211    uint8_t i;
    212 
    213    ILO_DEV_ASSERT(dev, 6, 8);
    214 
    215    for (i = 0; i < count; i++) {
    216       const struct ilo_state_viewport_scissor_info *scissor = &scissors[i];
    217       uint16_t min_x, min_y, max_x, max_y;
    218       uint32_t dw0, dw1;
    219 
    220       min_x = (scissor->min_x < max_size) ? scissor->min_x : max_size - 1;
    221       min_y = (scissor->min_y < max_size) ? scissor->min_y : max_size - 1;
    222       max_x = (scissor->max_x < max_size) ? scissor->max_x : max_size - 1;
    223       max_y = (scissor->max_y < max_size) ? scissor->max_y : max_size - 1;
    224 
    225       dw0 = min_y << GEN6_SCISSOR_DW0_MIN_Y__SHIFT |
    226             min_x << GEN6_SCISSOR_DW0_MIN_X__SHIFT;
    227       dw1 = max_y << GEN6_SCISSOR_DW1_MAX_Y__SHIFT |
    228             max_x << GEN6_SCISSOR_DW1_MAX_X__SHIFT;
    229 
    230       STATIC_ASSERT(ARRAY_SIZE(vp->scissor[i]) >= 2);
    231       vp->scissor[i][0] = dw0;
    232       vp->scissor[i][1] = dw1;
    233    }
    234 
    235    return true;
    236 }
    237 
    238 bool
    239 ilo_state_viewport_init(struct ilo_state_viewport *vp,
    240                         const struct ilo_dev *dev,
    241                         const struct ilo_state_viewport_info *info)
    242 {
    243    const size_t elem_size = ilo_state_viewport_data_size(dev, 1);
    244 
    245    assert(ilo_is_zeroed(vp, sizeof(*vp)));
    246    assert(ilo_is_zeroed(info->data, info->data_size));
    247 
    248    vp->data = info->data;
    249 
    250    if (info->data_size / elem_size < ILO_STATE_VIEWPORT_MAX_COUNT)
    251       vp->array_size = info->data_size / elem_size;
    252    else
    253       vp->array_size = ILO_STATE_VIEWPORT_MAX_COUNT;
    254 
    255    return ilo_state_viewport_set_params(vp, dev, &info->params, false);
    256 }
    257 
    258 bool
    259 ilo_state_viewport_init_data_only(struct ilo_state_viewport *vp,
    260                                   const struct ilo_dev *dev,
    261                                   void *data, size_t data_size)
    262 {
    263    struct ilo_state_viewport_info info;
    264 
    265    memset(&info, 0, sizeof(info));
    266    info.data = data;
    267    info.data_size = data_size;
    268 
    269    return ilo_state_viewport_init(vp, dev, &info);
    270 }
    271 
    272 bool
    273 ilo_state_viewport_init_for_rectlist(struct ilo_state_viewport *vp,
    274                                      const struct ilo_dev *dev,
    275                                      void *data, size_t data_size)
    276 {
    277    struct ilo_state_viewport_info info;
    278    struct ilo_state_viewport_matrix_info mat;
    279    struct ilo_state_viewport_scissor_info sci;
    280 
    281    memset(&info, 0, sizeof(info));
    282    memset(&mat, 0, sizeof(mat));
    283    memset(&sci, 0, sizeof(sci));
    284 
    285    info.data = data;
    286    info.data_size = data_size;
    287    info.params.matrices = &mat;
    288    info.params.scissors = &sci;
    289    info.params.count = 1;
    290 
    291    mat.scale[0] = 1.0f;
    292    mat.scale[1] = 1.0f;
    293    mat.scale[2] = 1.0f;
    294 
    295    return ilo_state_viewport_init(vp, dev, &info);
    296 }
    297 
    298 static void
    299 viewport_set_count(struct ilo_state_viewport *vp,
    300                    const struct ilo_dev *dev,
    301                    uint8_t count)
    302 {
    303    assert(count <= vp->array_size);
    304 
    305    vp->count = count;
    306    vp->sf_clip = (uint32_t (*)[16]) vp->data;
    307    vp->cc =      (uint32_t (*)[ 2]) (vp->sf_clip + count);
    308    vp->scissor = (uint32_t (*)[ 2]) (vp->cc + count);
    309 }
    310 
    311 bool
    312 ilo_state_viewport_set_params(struct ilo_state_viewport *vp,
    313                               const struct ilo_dev *dev,
    314                               const struct ilo_state_viewport_params_info *params,
    315                               bool scissors_only)
    316 {
    317    bool ret = true;
    318 
    319    if (scissors_only) {
    320       assert(vp->count == params->count);
    321 
    322       ret &= viewport_scissor_set_gen6_SCISSOR_RECT(vp, dev,
    323             params->scissors, params->count);
    324    } else {
    325       viewport_set_count(vp, dev, params->count);
    326 
    327       ret &= viewport_matrix_set_gen7_SF_CLIP_VIEWPORT(vp, dev,
    328             params->matrices, params->count);
    329       ret &= viewport_matrix_set_gen6_CC_VIEWPORT(vp, dev,
    330             params->matrices, params->count);
    331       ret &= viewport_scissor_set_gen6_SCISSOR_RECT(vp, dev,
    332             params->scissors, params->count);
    333    }
    334 
    335    assert(ret);
    336 
    337    return ret;
    338 }
    339 
    340 void
    341 ilo_state_viewport_full_delta(const struct ilo_state_viewport *vp,
    342                               const struct ilo_dev *dev,
    343                               struct ilo_state_viewport_delta *delta)
    344 {
    345    delta->dirty = ILO_STATE_VIEWPORT_SF_CLIP_VIEWPORT |
    346                   ILO_STATE_VIEWPORT_CC_VIEWPORT |
    347                   ILO_STATE_VIEWPORT_SCISSOR_RECT;
    348 }
    349 
    350 void
    351 ilo_state_viewport_get_delta(const struct ilo_state_viewport *vp,
    352                              const struct ilo_dev *dev,
    353                              const struct ilo_state_viewport *old,
    354                              struct ilo_state_viewport_delta *delta)
    355 {
    356    const size_t sf_clip_size = sizeof(vp->sf_clip[0]) * vp->count;
    357    const size_t cc_size = sizeof(vp->cc[0]) * vp->count;
    358    const size_t scissor_size = sizeof(vp->scissor[0]) * vp->count;
    359 
    360    /* no shallow copying */
    361    assert(vp->data != old->data);
    362 
    363    if (vp->count != old->count) {
    364       ilo_state_viewport_full_delta(vp, dev, delta);
    365       return;
    366    }
    367 
    368    delta->dirty = 0;
    369 
    370    if (memcmp(vp->sf_clip, old->sf_clip, sf_clip_size))
    371       delta->dirty |= ILO_STATE_VIEWPORT_SF_CLIP_VIEWPORT;
    372 
    373    if (memcmp(vp->cc, old->cc, cc_size))
    374       delta->dirty |= ILO_STATE_VIEWPORT_CC_VIEWPORT;
    375 
    376    if (memcmp(vp->scissor, old->scissor, scissor_size))
    377       delta->dirty |= ILO_STATE_VIEWPORT_SCISSOR_RECT;
    378 }
    379