Home | History | Annotate | Download | only in radeon
      1 /*
      2  * Copyright  2009 Red Hat Inc.
      3  * All Rights Reserved.
      4  *
      5  * Permission is hereby granted, free of charge, to any person obtaining
      6  * a copy of this software and associated documentation files (the
      7  * "Software"), to deal in the Software without restriction, including
      8  * without limitation the rights to use, copy, modify, merge, publish,
      9  * distribute, sub license, and/or sell copies of the Software, and to
     10  * permit persons to whom the Software is furnished to do so, subject to
     11  * the following conditions:
     12  *
     13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     14  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
     15  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
     16  * NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS, AUTHORS
     17  * AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     19  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
     20  * USE OR OTHER DEALINGS IN THE SOFTWARE.
     21  *
     22  * The above copyright notice and this permission notice (including the
     23  * next paragraph) shall be included in all copies or substantial portions
     24  * of the Software.
     25  */
     26 /*
     27  */
     28 #ifdef HAVE_CONFIG_H
     29 #include <config.h>
     30 #endif
     31 #include <assert.h>
     32 #include <errno.h>
     33 #include <stdlib.h>
     34 #include "libdrm_macros.h"
     35 #include "radeon_cs.h"
     36 #include "radeon_bo_int.h"
     37 #include "radeon_cs_int.h"
     38 
     39 struct rad_sizes {
     40     int32_t op_read;
     41     int32_t op_gart_write;
     42     int32_t op_vram_write;
     43 };
     44 
     45 static inline int radeon_cs_setup_bo(struct radeon_cs_space_check *sc, struct rad_sizes *sizes)
     46 {
     47     uint32_t read_domains, write_domain;
     48     struct radeon_bo_int *bo;
     49 
     50     bo = sc->bo;
     51     sc->new_accounted = 0;
     52     read_domains = sc->read_domains;
     53     write_domain = sc->write_domain;
     54 
     55     /* legacy needs a static check */
     56     if (radeon_bo_is_static((struct radeon_bo *)sc->bo)) {
     57         bo->space_accounted = sc->new_accounted = (read_domains << 16) | write_domain;
     58         return 0;
     59     }
     60 
     61     /* already accounted this bo */
     62     if (write_domain && (write_domain == bo->space_accounted)) {
     63         sc->new_accounted = bo->space_accounted;
     64         return 0;
     65     }
     66     if (read_domains && ((read_domains << 16) == bo->space_accounted)) {
     67         sc->new_accounted = bo->space_accounted;
     68         return 0;
     69     }
     70 
     71     if (bo->space_accounted == 0) {
     72         if (write_domain) {
     73             if (write_domain == RADEON_GEM_DOMAIN_VRAM)
     74                 sizes->op_vram_write += bo->size;
     75             else if (write_domain == RADEON_GEM_DOMAIN_GTT)
     76                 sizes->op_gart_write += bo->size;
     77             sc->new_accounted = write_domain;
     78         } else {
     79             sizes->op_read += bo->size;
     80             sc->new_accounted = read_domains << 16;
     81         }
     82     } else {
     83         uint16_t old_read, old_write;
     84 
     85         old_read = bo->space_accounted >> 16;
     86         old_write = bo->space_accounted & 0xffff;
     87 
     88         if (write_domain && (old_read & write_domain)) {
     89             sc->new_accounted = write_domain;
     90             /* moving from read to a write domain */
     91             if (write_domain == RADEON_GEM_DOMAIN_VRAM) {
     92                 sizes->op_read -= bo->size;
     93                 sizes->op_vram_write += bo->size;
     94             } else if (write_domain == RADEON_GEM_DOMAIN_GTT) {
     95                 sizes->op_read -= bo->size;
     96                 sizes->op_gart_write += bo->size;
     97             }
     98         } else if (read_domains & old_write) {
     99             sc->new_accounted = bo->space_accounted & 0xffff;
    100         } else {
    101             /* rewrite the domains */
    102             if (write_domain != old_write)
    103                 fprintf(stderr,"WRITE DOMAIN RELOC FAILURE 0x%x %d %d\n", bo->handle, write_domain, old_write);
    104             if (read_domains != old_read)
    105                fprintf(stderr,"READ DOMAIN RELOC FAILURE 0x%x %d %d\n", bo->handle, read_domains, old_read);
    106             return RADEON_CS_SPACE_FLUSH;
    107         }
    108     }
    109     return 0;
    110 }
    111 
    112 static int radeon_cs_do_space_check(struct radeon_cs_int *cs, struct radeon_cs_space_check *new_tmp)
    113 {
    114     struct radeon_cs_manager *csm = cs->csm;
    115     int i;
    116     struct radeon_bo_int *bo;
    117     struct rad_sizes sizes;
    118     int ret;
    119 
    120     /* check the totals for this operation */
    121 
    122     if (cs->bo_count == 0 && !new_tmp)
    123         return 0;
    124 
    125     memset(&sizes, 0, sizeof(struct rad_sizes));
    126 
    127     /* prepare */
    128     for (i = 0; i < cs->bo_count; i++) {
    129         ret = radeon_cs_setup_bo(&cs->bos[i], &sizes);
    130         if (ret)
    131             return ret;
    132     }
    133 
    134     if (new_tmp) {
    135         ret = radeon_cs_setup_bo(new_tmp, &sizes);
    136         if (ret)
    137             return ret;
    138     }
    139 
    140     if (sizes.op_read < 0)
    141         sizes.op_read = 0;
    142 
    143     /* check sizes - operation first */
    144     if ((sizes.op_read + sizes.op_gart_write > csm->gart_limit) ||
    145         (sizes.op_vram_write > csm->vram_limit)) {
    146         return RADEON_CS_SPACE_OP_TO_BIG;
    147     }
    148 
    149     if (((csm->vram_write_used + sizes.op_vram_write) > csm->vram_limit) ||
    150         ((csm->read_used + csm->gart_write_used + sizes.op_gart_write + sizes.op_read) > csm->gart_limit)) {
    151         return RADEON_CS_SPACE_FLUSH;
    152     }
    153 
    154     csm->gart_write_used += sizes.op_gart_write;
    155     csm->vram_write_used += sizes.op_vram_write;
    156     csm->read_used += sizes.op_read;
    157     /* commit */
    158     for (i = 0; i < cs->bo_count; i++) {
    159         bo = cs->bos[i].bo;
    160         bo->space_accounted = cs->bos[i].new_accounted;
    161     }
    162     if (new_tmp)
    163         new_tmp->bo->space_accounted = new_tmp->new_accounted;
    164 
    165     return RADEON_CS_SPACE_OK;
    166 }
    167 
    168 void
    169 radeon_cs_space_add_persistent_bo(struct radeon_cs *cs, struct radeon_bo *bo,
    170                                   uint32_t read_domains, uint32_t write_domain)
    171 {
    172     struct radeon_cs_int *csi = (struct radeon_cs_int *)cs;
    173     struct radeon_bo_int *boi = (struct radeon_bo_int *)bo;
    174     int i;
    175     for (i = 0; i < csi->bo_count; i++) {
    176         if (csi->bos[i].bo == boi &&
    177             csi->bos[i].read_domains == read_domains &&
    178             csi->bos[i].write_domain == write_domain)
    179             return;
    180     }
    181     radeon_bo_ref(bo);
    182     i = csi->bo_count;
    183     csi->bos[i].bo = boi;
    184     csi->bos[i].read_domains = read_domains;
    185     csi->bos[i].write_domain = write_domain;
    186     csi->bos[i].new_accounted = 0;
    187     csi->bo_count++;
    188 
    189     assert(csi->bo_count < MAX_SPACE_BOS);
    190 }
    191 
    192 static int radeon_cs_check_space_internal(struct radeon_cs_int *cs,
    193                       struct radeon_cs_space_check *tmp_bo)
    194 {
    195     int ret;
    196     int flushed = 0;
    197 
    198 again:
    199     ret = radeon_cs_do_space_check(cs, tmp_bo);
    200     if (ret == RADEON_CS_SPACE_OP_TO_BIG)
    201         return -1;
    202     if (ret == RADEON_CS_SPACE_FLUSH) {
    203         (*cs->space_flush_fn)(cs->space_flush_data);
    204         if (flushed)
    205             return -1;
    206         flushed = 1;
    207         goto again;
    208     }
    209     return 0;
    210 }
    211 
    212 int
    213 radeon_cs_space_check_with_bo(struct radeon_cs *cs, struct radeon_bo *bo,
    214                               uint32_t read_domains, uint32_t write_domain)
    215 {
    216     struct radeon_cs_int *csi = (struct radeon_cs_int *)cs;
    217     struct radeon_bo_int *boi = (struct radeon_bo_int *)bo;
    218     struct radeon_cs_space_check temp_bo;
    219 
    220     int ret = 0;
    221 
    222     if (bo) {
    223         temp_bo.bo = boi;
    224         temp_bo.read_domains = read_domains;
    225         temp_bo.write_domain = write_domain;
    226         temp_bo.new_accounted = 0;
    227     }
    228 
    229     ret = radeon_cs_check_space_internal(csi, bo ? &temp_bo : NULL);
    230     return ret;
    231 }
    232 
    233 int radeon_cs_space_check(struct radeon_cs *cs)
    234 {
    235     struct radeon_cs_int *csi = (struct radeon_cs_int *)cs;
    236     return radeon_cs_check_space_internal(csi, NULL);
    237 }
    238 
    239 void radeon_cs_space_reset_bos(struct radeon_cs *cs)
    240 {
    241     struct radeon_cs_int *csi = (struct radeon_cs_int *)cs;
    242     int i;
    243     for (i = 0; i < csi->bo_count; i++) {
    244         radeon_bo_unref((struct radeon_bo *)csi->bos[i].bo);
    245         csi->bos[i].bo = NULL;
    246         csi->bos[i].read_domains = 0;
    247         csi->bos[i].write_domain = 0;
    248         csi->bos[i].new_accounted = 0;
    249     }
    250     csi->bo_count = 0;
    251 }
    252