radeon: align r600 msaa buffers to a multiple of macrotile size * num samples
[profile/ivi/libdrm.git] / radeon / radeon_cs_space.c
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 #include <assert.h>
29 #include <errno.h>
30 #include <stdlib.h>
31 #include "radeon_cs.h"
32 #include "radeon_bo_int.h"
33 #include "radeon_cs_int.h"
34
35 struct rad_sizes {
36     int32_t op_read;
37     int32_t op_gart_write;
38     int32_t op_vram_write;
39 };
40
41 static inline int radeon_cs_setup_bo(struct radeon_cs_space_check *sc, struct rad_sizes *sizes)
42 {
43     uint32_t read_domains, write_domain;
44     struct radeon_bo_int *bo;
45
46     bo = sc->bo;
47     sc->new_accounted = 0;
48     read_domains = sc->read_domains;
49     write_domain = sc->write_domain;
50
51     /* legacy needs a static check */
52     if (radeon_bo_is_static((struct radeon_bo *)sc->bo)) {
53         bo->space_accounted = sc->new_accounted = (read_domains << 16) | write_domain;
54         return 0;
55     }
56
57     /* already accounted this bo */
58     if (write_domain && (write_domain == bo->space_accounted)) {
59         sc->new_accounted = bo->space_accounted;
60         return 0;
61     }
62     if (read_domains && ((read_domains << 16) == bo->space_accounted)) {
63         sc->new_accounted = bo->space_accounted;
64         return 0;
65     }
66
67     if (bo->space_accounted == 0) {
68         if (write_domain) {
69             if (write_domain == RADEON_GEM_DOMAIN_VRAM)
70                 sizes->op_vram_write += bo->size;
71             else if (write_domain == RADEON_GEM_DOMAIN_GTT)
72                 sizes->op_gart_write += bo->size;
73             sc->new_accounted = write_domain;
74         } else {
75             sizes->op_read += bo->size;
76             sc->new_accounted = read_domains << 16;
77         }
78     } else {
79         uint16_t old_read, old_write;
80
81         old_read = bo->space_accounted >> 16;
82         old_write = bo->space_accounted & 0xffff;
83
84         if (write_domain && (old_read & write_domain)) {
85             sc->new_accounted = write_domain;
86             /* moving from read to a write domain */
87             if (write_domain == RADEON_GEM_DOMAIN_VRAM) {
88                 sizes->op_read -= bo->size;
89                 sizes->op_vram_write += bo->size;
90             } else if (write_domain == RADEON_GEM_DOMAIN_GTT) {
91                 sizes->op_read -= bo->size;
92                 sizes->op_gart_write += bo->size;
93             }
94         } else if (read_domains & old_write) {
95             sc->new_accounted = bo->space_accounted & 0xffff;
96         } else {
97             /* rewrite the domains */
98             if (write_domain != old_write)
99                 fprintf(stderr,"WRITE DOMAIN RELOC FAILURE 0x%x %d %d\n", bo->handle, write_domain, old_write);
100             if (read_domains != old_read)
101                fprintf(stderr,"READ DOMAIN RELOC FAILURE 0x%x %d %d\n", bo->handle, read_domains, old_read);
102             return RADEON_CS_SPACE_FLUSH;
103         }
104     }
105     return 0;
106 }
107
108 static int radeon_cs_do_space_check(struct radeon_cs_int *cs, struct radeon_cs_space_check *new_tmp)
109 {
110     struct radeon_cs_manager *csm = cs->csm;
111     int i;
112     struct radeon_bo_int *bo;
113     struct rad_sizes sizes;
114     int ret;
115
116     /* check the totals for this operation */
117
118     if (cs->bo_count == 0 && !new_tmp)
119         return 0;
120
121     memset(&sizes, 0, sizeof(struct rad_sizes));
122
123     /* prepare */
124     for (i = 0; i < cs->bo_count; i++) {
125         ret = radeon_cs_setup_bo(&cs->bos[i], &sizes);
126         if (ret)
127             return ret;
128     }
129
130     if (new_tmp) {
131         ret = radeon_cs_setup_bo(new_tmp, &sizes);
132         if (ret)
133             return ret;
134     }
135
136     if (sizes.op_read < 0)
137         sizes.op_read = 0;
138
139     /* check sizes - operation first */
140     if ((sizes.op_read + sizes.op_gart_write > csm->gart_limit) ||
141         (sizes.op_vram_write > csm->vram_limit)) {
142         return RADEON_CS_SPACE_OP_TO_BIG;
143     }
144
145     if (((csm->vram_write_used + sizes.op_vram_write) > csm->vram_limit) ||
146         ((csm->read_used + csm->gart_write_used + sizes.op_gart_write + sizes.op_read) > csm->gart_limit)) {
147         return RADEON_CS_SPACE_FLUSH;
148     }
149
150     csm->gart_write_used += sizes.op_gart_write;
151     csm->vram_write_used += sizes.op_vram_write;
152     csm->read_used += sizes.op_read;
153     /* commit */
154     for (i = 0; i < cs->bo_count; i++) {
155         bo = cs->bos[i].bo;
156         bo->space_accounted = cs->bos[i].new_accounted;
157     }
158     if (new_tmp)
159         new_tmp->bo->space_accounted = new_tmp->new_accounted;
160
161     return RADEON_CS_SPACE_OK;
162 }
163
164 void radeon_cs_space_add_persistent_bo(struct radeon_cs *cs, struct radeon_bo *bo, uint32_t read_domains, uint32_t write_domain)
165 {
166     struct radeon_cs_int *csi = (struct radeon_cs_int *)cs;
167     struct radeon_bo_int *boi = (struct radeon_bo_int *)bo;
168     int i;
169     for (i = 0; i < csi->bo_count; i++) {
170         if (csi->bos[i].bo == boi &&
171             csi->bos[i].read_domains == read_domains &&
172             csi->bos[i].write_domain == write_domain)
173             return;
174     }
175     radeon_bo_ref(bo);
176     i = csi->bo_count;
177     csi->bos[i].bo = boi;
178     csi->bos[i].read_domains = read_domains;
179     csi->bos[i].write_domain = write_domain;
180     csi->bos[i].new_accounted = 0;
181     csi->bo_count++;
182
183     assert(csi->bo_count < MAX_SPACE_BOS);
184 }
185
186 static int radeon_cs_check_space_internal(struct radeon_cs_int *cs,
187                       struct radeon_cs_space_check *tmp_bo)
188 {
189     int ret;
190     int flushed = 0;
191
192 again:
193     ret = radeon_cs_do_space_check(cs, tmp_bo);
194     if (ret == RADEON_CS_SPACE_OP_TO_BIG)
195         return -1;
196     if (ret == RADEON_CS_SPACE_FLUSH) {
197         (*cs->space_flush_fn)(cs->space_flush_data);
198         if (flushed)
199             return -1;
200         flushed = 1;
201         goto again;
202     }
203     return 0;
204 }
205
206 int radeon_cs_space_check_with_bo(struct radeon_cs *cs,
207                   struct radeon_bo *bo,
208                   uint32_t read_domains, uint32_t write_domain)
209 {
210     struct radeon_cs_int *csi = (struct radeon_cs_int *)cs;
211     struct radeon_bo_int *boi = (struct radeon_bo_int *)bo;
212     struct radeon_cs_space_check temp_bo;
213
214     int ret = 0;
215
216     if (bo) {
217         temp_bo.bo = boi;
218         temp_bo.read_domains = read_domains;
219         temp_bo.write_domain = write_domain;
220         temp_bo.new_accounted = 0;
221     }
222
223     ret = radeon_cs_check_space_internal(csi, bo ? &temp_bo : NULL);
224     return ret;
225 }
226
227 int radeon_cs_space_check(struct radeon_cs *cs)
228 {
229     struct radeon_cs_int *csi = (struct radeon_cs_int *)cs;
230     return radeon_cs_check_space_internal(csi, NULL);
231 }
232
233 void radeon_cs_space_reset_bos(struct radeon_cs *cs)
234 {
235     struct radeon_cs_int *csi = (struct radeon_cs_int *)cs;
236     int i;
237     for (i = 0; i < csi->bo_count; i++) {
238         radeon_bo_unref((struct radeon_bo *)csi->bos[i].bo);
239         csi->bos[i].bo = NULL;
240         csi->bos[i].read_domains = 0;
241         csi->bos[i].write_domain = 0;
242         csi->bos[i].new_accounted = 0;
243     }
244     csi->bo_count = 0;
245 }