874a0927388e5abf05069cde58af093afb8a63d8
1 /*
2 * Copyright © 2011 Red Hat All Rights Reserved.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files (the
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sub license, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
14 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15 * NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS, AUTHORS
16 * AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
18 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
19 * USE OR OTHER DEALINGS IN THE SOFTWARE.
20 *
21 * The above copyright notice and this permission notice (including the
22 * next paragraph) shall be included in all copies or substantial portions
23 * of the Software.
24 */
25 /*
26 * Authors:
27 * Jérôme Glisse <jglisse@redhat.com>
28 */
29 #include <errno.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <sys/mman.h>
34 #include <sys/ioctl.h>
35 #include "drm.h"
36 #include "xf86drm.h"
37 #include "radeon_drm.h"
38 #include "radeon_surface.h"
40 #define ALIGN(value, alignment) (((value) + alignment - 1) & ~(alignment - 1))
41 #define MAX2(A, B) ((A) > (B) ? (A) : (B))
42 #define MIN2(A, B) ((A) < (B) ? (A) : (B))
44 /* keep this private */
45 enum radeon_family {
46 CHIP_UNKNOWN,
47 CHIP_R600,
48 CHIP_RV610,
49 CHIP_RV630,
50 CHIP_RV670,
51 CHIP_RV620,
52 CHIP_RV635,
53 CHIP_RS780,
54 CHIP_RS880,
55 CHIP_RV770,
56 CHIP_RV730,
57 CHIP_RV710,
58 CHIP_RV740,
59 CHIP_CEDAR,
60 CHIP_REDWOOD,
61 CHIP_JUNIPER,
62 CHIP_CYPRESS,
63 CHIP_HEMLOCK,
64 CHIP_PALM,
65 CHIP_SUMO,
66 CHIP_SUMO2,
67 CHIP_BARTS,
68 CHIP_TURKS,
69 CHIP_CAICOS,
70 CHIP_CAYMAN,
71 CHIP_ARUBA,
72 CHIP_TAHITI,
73 CHIP_PITCAIRN,
74 CHIP_VERDE,
75 CHIP_LAST,
76 };
78 typedef int (*hw_init_surface_t)(struct radeon_surface_manager *surf_man,
79 struct radeon_surface *surf);
80 typedef int (*hw_best_surface_t)(struct radeon_surface_manager *surf_man,
81 struct radeon_surface *surf);
83 struct radeon_hw_info {
84 /* apply to r6, eg */
85 uint32_t group_bytes;
86 uint32_t num_banks;
87 uint32_t num_pipes;
88 /* apply to eg */
89 uint32_t row_size;
90 unsigned allow_2d;
91 };
93 struct radeon_surface_manager {
94 int fd;
95 uint32_t device_id;
96 struct radeon_hw_info hw_info;
97 unsigned family;
98 hw_init_surface_t surface_init;
99 hw_best_surface_t surface_best;
100 };
102 /* helper */
103 static int radeon_get_value(int fd, unsigned req, uint32_t *value)
104 {
105 struct drm_radeon_info info = {};
106 int r;
108 *value = 0;
109 info.request = req;
110 info.value = (uintptr_t)value;
111 r = drmCommandWriteRead(fd, DRM_RADEON_INFO, &info,
112 sizeof(struct drm_radeon_info));
113 return r;
114 }
116 static int radeon_get_family(struct radeon_surface_manager *surf_man)
117 {
118 switch (surf_man->device_id) {
119 #define CHIPSET(pci_id, name, fam) case pci_id: surf_man->family = CHIP_##fam; break;
120 #include "r600_pci_ids.h"
121 #undef CHIPSET
122 default:
123 return -EINVAL;
124 }
125 return 0;
126 }
128 static unsigned next_power_of_two(unsigned x)
129 {
130 if (x <= 1)
131 return 1;
133 return (1 << ((sizeof(unsigned) * 8) - __builtin_clz(x - 1)));
134 }
136 static unsigned mip_minify(unsigned size, unsigned level)
137 {
138 unsigned val;
140 val = MAX2(1, size >> level);
141 if (level > 0)
142 val = next_power_of_two(val);
143 return val;
144 }
146 static void surf_minify(struct radeon_surface *surf,
147 unsigned level,
148 uint32_t xalign, uint32_t yalign, uint32_t zalign,
149 unsigned offset)
150 {
151 surf->level[level].npix_x = mip_minify(surf->npix_x, level);
152 surf->level[level].npix_y = mip_minify(surf->npix_y, level);
153 surf->level[level].npix_z = mip_minify(surf->npix_z, level);
154 surf->level[level].nblk_x = (surf->level[level].npix_x + surf->blk_w - 1) / surf->blk_w;
155 surf->level[level].nblk_y = (surf->level[level].npix_y + surf->blk_h - 1) / surf->blk_h;
156 surf->level[level].nblk_z = (surf->level[level].npix_z + surf->blk_d - 1) / surf->blk_d;
157 if (surf->level[level].mode == RADEON_SURF_MODE_2D) {
158 if (surf->level[level].nblk_x < xalign || surf->level[level].nblk_y < yalign) {
159 surf->level[level].mode = RADEON_SURF_MODE_1D;
160 return;
161 }
162 }
163 surf->level[level].nblk_x = ALIGN(surf->level[level].nblk_x, xalign);
164 surf->level[level].nblk_y = ALIGN(surf->level[level].nblk_y, yalign);
165 surf->level[level].nblk_z = ALIGN(surf->level[level].nblk_z, zalign);
167 surf->level[level].offset = offset;
168 surf->level[level].pitch_bytes = surf->level[level].nblk_x * surf->bpe;
169 surf->level[level].slice_size = surf->level[level].pitch_bytes * surf->level[level].nblk_y;
171 surf->bo_size = offset + surf->level[level].slice_size * surf->level[level].nblk_z * surf->array_size;
172 }
174 /* ===========================================================================
175 * r600/r700 family
176 */
177 static int r6_init_hw_info(struct radeon_surface_manager *surf_man)
178 {
179 uint32_t tiling_config;
180 drmVersionPtr version;
181 int r;
183 r = radeon_get_value(surf_man->fd, RADEON_INFO_TILING_CONFIG,
184 &tiling_config);
185 if (r) {
186 return r;
187 }
189 surf_man->hw_info.allow_2d = 0;
190 version = drmGetVersion(surf_man->fd);
191 if (version && version->version_minor >= 14) {
192 surf_man->hw_info.allow_2d = 1;
193 }
194 drmFreeVersion(version);
196 switch ((tiling_config & 0xe) >> 1) {
197 case 0:
198 surf_man->hw_info.num_pipes = 1;
199 break;
200 case 1:
201 surf_man->hw_info.num_pipes = 2;
202 break;
203 case 2:
204 surf_man->hw_info.num_pipes = 4;
205 break;
206 case 3:
207 surf_man->hw_info.num_pipes = 8;
208 break;
209 default:
210 surf_man->hw_info.num_pipes = 8;
211 surf_man->hw_info.allow_2d = 0;
212 break;
213 }
215 switch ((tiling_config & 0x30) >> 4) {
216 case 0:
217 surf_man->hw_info.num_banks = 4;
218 break;
219 case 1:
220 surf_man->hw_info.num_banks = 8;
221 break;
222 default:
223 surf_man->hw_info.num_banks = 8;
224 surf_man->hw_info.allow_2d = 0;
225 break;
226 }
228 switch ((tiling_config & 0xc0) >> 6) {
229 case 0:
230 surf_man->hw_info.group_bytes = 256;
231 break;
232 case 1:
233 surf_man->hw_info.group_bytes = 512;
234 break;
235 default:
236 surf_man->hw_info.group_bytes = 256;
237 surf_man->hw_info.allow_2d = 0;
238 break;
239 }
240 return 0;
241 }
243 static int r6_surface_init_linear(struct radeon_surface_manager *surf_man,
244 struct radeon_surface *surf,
245 uint64_t offset, unsigned start_level)
246 {
247 uint32_t xalign, yalign, zalign;
248 unsigned i;
250 /* compute alignment */
251 if (!start_level) {
252 surf->bo_alignment = MAX2(256, surf_man->hw_info.group_bytes);
253 }
254 /* the 32 alignment is for scanout, cb or db but to allow texture to be
255 * easily bound as such we force this alignment to all surface
256 */
257 xalign = MAX2(1, surf_man->hw_info.group_bytes / surf->bpe);
258 yalign = 1;
259 zalign = 1;
260 if (surf->flags & RADEON_SURF_SCANOUT) {
261 xalign = MAX2((surf->bpe == 1) ? 64 : 32, xalign);
262 }
264 /* build mipmap tree */
265 for (i = start_level; i <= surf->last_level; i++) {
266 surf->level[i].mode = RADEON_SURF_MODE_LINEAR;
267 surf_minify(surf, i, xalign, yalign, zalign, offset);
268 /* level0 and first mipmap need to have alignment */
269 offset = surf->bo_size;
270 if ((i == 0)) {
271 offset = ALIGN(offset, surf->bo_alignment);
272 }
273 }
274 return 0;
275 }
277 static int r6_surface_init_linear_aligned(struct radeon_surface_manager *surf_man,
278 struct radeon_surface *surf,
279 uint64_t offset, unsigned start_level)
280 {
281 uint32_t xalign, yalign, zalign;
282 unsigned i;
284 /* compute alignment */
285 if (!start_level) {
286 surf->bo_alignment = MAX2(256, surf_man->hw_info.group_bytes);
287 }
288 xalign = MAX2(64, surf_man->hw_info.group_bytes / surf->bpe);
289 yalign = 1;
290 zalign = 1;
292 /* build mipmap tree */
293 for (i = start_level; i <= surf->last_level; i++) {
294 surf->level[i].mode = RADEON_SURF_MODE_LINEAR_ALIGNED;
295 surf_minify(surf, i, xalign, yalign, zalign, offset);
296 /* level0 and first mipmap need to have alignment */
297 offset = surf->bo_size;
298 if ((i == 0)) {
299 offset = ALIGN(offset, surf->bo_alignment);
300 }
301 }
302 return 0;
303 }
305 static int r6_surface_init_1d(struct radeon_surface_manager *surf_man,
306 struct radeon_surface *surf,
307 uint64_t offset, unsigned start_level)
308 {
309 uint32_t xalign, yalign, zalign, tilew;
310 unsigned i;
312 /* compute alignment */
313 tilew = 8;
314 xalign = surf_man->hw_info.group_bytes / (tilew * surf->bpe * surf->nsamples);
315 xalign = MAX2(tilew, xalign);
316 yalign = tilew;
317 zalign = 1;
318 if (surf->flags & RADEON_SURF_SCANOUT) {
319 xalign = MAX2((surf->bpe == 1) ? 64 : 32, xalign);
320 }
321 if (!start_level) {
322 surf->bo_alignment = MAX2(256, surf_man->hw_info.group_bytes);
323 }
325 /* build mipmap tree */
326 for (i = start_level; i <= surf->last_level; i++) {
327 surf->level[i].mode = RADEON_SURF_MODE_1D;
328 surf_minify(surf, i, xalign, yalign, zalign, offset);
329 /* level0 and first mipmap need to have alignment */
330 offset = surf->bo_size;
331 if ((i == 0)) {
332 offset = ALIGN(offset, surf->bo_alignment);
333 }
334 }
335 return 0;
336 }
338 static int r6_surface_init_2d(struct radeon_surface_manager *surf_man,
339 struct radeon_surface *surf,
340 uint64_t offset, unsigned start_level)
341 {
342 uint32_t xalign, yalign, zalign, tilew;
343 unsigned i;
345 /* compute alignment */
346 tilew = 8;
347 zalign = 1;
348 xalign = (surf_man->hw_info.group_bytes * surf_man->hw_info.num_banks) /
349 (tilew * surf->bpe * surf->nsamples);
350 xalign = MAX2(tilew * surf_man->hw_info.num_banks, xalign);
351 yalign = tilew * surf_man->hw_info.num_pipes;
352 if (surf->flags & RADEON_SURF_SCANOUT) {
353 xalign = MAX2((surf->bpe == 1) ? 64 : 32, xalign);
354 }
355 if (!start_level) {
356 surf->bo_alignment =
357 MAX2(surf_man->hw_info.num_pipes *
358 surf_man->hw_info.num_banks *
359 surf->bpe * 64,
360 xalign * yalign * surf->nsamples * surf->bpe);
361 }
363 /* build mipmap tree */
364 for (i = start_level; i <= surf->last_level; i++) {
365 surf->level[i].mode = RADEON_SURF_MODE_2D;
366 surf_minify(surf, i, xalign, yalign, zalign, offset);
367 if (surf->level[i].mode == RADEON_SURF_MODE_1D) {
368 return r6_surface_init_1d(surf_man, surf, offset, i);
369 }
370 /* level0 and first mipmap need to have alignment */
371 offset = surf->bo_size;
372 if ((i == 0)) {
373 offset = ALIGN(offset, surf->bo_alignment);
374 }
375 }
376 return 0;
377 }
379 static int r6_surface_init(struct radeon_surface_manager *surf_man,
380 struct radeon_surface *surf)
381 {
382 unsigned mode;
383 int r;
385 /* tiling mode */
386 mode = (surf->flags >> RADEON_SURF_MODE_SHIFT) & RADEON_SURF_MODE_MASK;
388 if (surf->flags & (RADEON_SURF_ZBUFFER | RADEON_SURF_SBUFFER)) {
389 /* zbuffer only support 1D or 2D tiled surface */
390 switch (mode) {
391 case RADEON_SURF_MODE_1D:
392 case RADEON_SURF_MODE_2D:
393 break;
394 default:
395 mode = RADEON_SURF_MODE_1D;
396 surf->flags = RADEON_SURF_CLR(surf->flags, MODE);
397 surf->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_1D, MODE);
398 break;
399 }
400 }
402 /* force 1d on kernel that can't do 2d */
403 if (!surf_man->hw_info.allow_2d && mode > RADEON_SURF_MODE_1D) {
404 mode = RADEON_SURF_MODE_1D;
405 surf->flags = RADEON_SURF_CLR(surf->flags, MODE);
406 surf->flags |= RADEON_SURF_SET(mode, MODE);
407 }
409 /* check surface dimension */
410 if (surf->npix_x > 8192 || surf->npix_y > 8192 || surf->npix_z > 8192) {
411 return -EINVAL;
412 }
414 /* check mipmap last_level */
415 if (surf->last_level > 14) {
416 return -EINVAL;
417 }
419 /* check tiling mode */
420 switch (mode) {
421 case RADEON_SURF_MODE_LINEAR:
422 r = r6_surface_init_linear(surf_man, surf, 0, 0);
423 break;
424 case RADEON_SURF_MODE_LINEAR_ALIGNED:
425 r = r6_surface_init_linear_aligned(surf_man, surf, 0, 0);
426 break;
427 case RADEON_SURF_MODE_1D:
428 r = r6_surface_init_1d(surf_man, surf, 0, 0);
429 break;
430 case RADEON_SURF_MODE_2D:
431 r = r6_surface_init_2d(surf_man, surf, 0, 0);
432 break;
433 default:
434 return -EINVAL;
435 }
436 return r;
437 }
439 static int r6_surface_best(struct radeon_surface_manager *surf_man,
440 struct radeon_surface *surf)
441 {
442 /* no value to optimize for r6xx/r7xx */
443 return 0;
444 }
447 /* ===========================================================================
448 * evergreen family
449 */
450 static int eg_init_hw_info(struct radeon_surface_manager *surf_man)
451 {
452 uint32_t tiling_config;
453 drmVersionPtr version;
454 int r;
456 r = radeon_get_value(surf_man->fd, RADEON_INFO_TILING_CONFIG,
457 &tiling_config);
458 if (r) {
459 return r;
460 }
462 surf_man->hw_info.allow_2d = 0;
463 version = drmGetVersion(surf_man->fd);
464 if (version && version->version_minor >= 16) {
465 surf_man->hw_info.allow_2d = 1;
466 }
467 drmFreeVersion(version);
469 switch (tiling_config & 0xf) {
470 case 0:
471 surf_man->hw_info.num_pipes = 1;
472 break;
473 case 1:
474 surf_man->hw_info.num_pipes = 2;
475 break;
476 case 2:
477 surf_man->hw_info.num_pipes = 4;
478 break;
479 case 3:
480 surf_man->hw_info.num_pipes = 8;
481 break;
482 default:
483 surf_man->hw_info.num_pipes = 8;
484 surf_man->hw_info.allow_2d = 0;
485 break;
486 }
488 switch ((tiling_config & 0xf0) >> 4) {
489 case 0:
490 surf_man->hw_info.num_banks = 4;
491 break;
492 case 1:
493 surf_man->hw_info.num_banks = 8;
494 break;
495 case 2:
496 surf_man->hw_info.num_banks = 16;
497 break;
498 default:
499 surf_man->hw_info.num_banks = 8;
500 surf_man->hw_info.allow_2d = 0;
501 break;
502 }
504 switch ((tiling_config & 0xf00) >> 8) {
505 case 0:
506 surf_man->hw_info.group_bytes = 256;
507 break;
508 case 1:
509 surf_man->hw_info.group_bytes = 512;
510 break;
511 default:
512 surf_man->hw_info.group_bytes = 256;
513 surf_man->hw_info.allow_2d = 0;
514 break;
515 }
517 switch ((tiling_config & 0xf000) >> 12) {
518 case 0:
519 surf_man->hw_info.row_size = 1024;
520 break;
521 case 1:
522 surf_man->hw_info.row_size = 2048;
523 break;
524 case 2:
525 surf_man->hw_info.row_size = 4096;
526 break;
527 default:
528 surf_man->hw_info.row_size = 4096;
529 surf_man->hw_info.allow_2d = 0;
530 break;
531 }
532 return 0;
533 }
535 static void eg_surf_minify(struct radeon_surface *surf,
536 unsigned level,
537 unsigned slice_pt,
538 unsigned mtilew,
539 unsigned mtileh,
540 unsigned mtileb,
541 unsigned offset)
542 {
543 unsigned mtile_pr, mtile_ps;
545 surf->level[level].npix_x = mip_minify(surf->npix_x, level);
546 surf->level[level].npix_y = mip_minify(surf->npix_y, level);
547 surf->level[level].npix_z = mip_minify(surf->npix_z, level);
548 surf->level[level].nblk_x = (surf->level[level].npix_x + surf->blk_w - 1) / surf->blk_w;
549 surf->level[level].nblk_y = (surf->level[level].npix_y + surf->blk_h - 1) / surf->blk_h;
550 surf->level[level].nblk_z = (surf->level[level].npix_z + surf->blk_d - 1) / surf->blk_d;
551 if (surf->level[level].mode == RADEON_SURF_MODE_2D) {
552 if (surf->level[level].nblk_x < mtilew || surf->level[level].nblk_y < mtileh) {
553 surf->level[level].mode = RADEON_SURF_MODE_1D;
554 return;
555 }
556 }
557 surf->level[level].nblk_x = ALIGN(surf->level[level].nblk_x, mtilew);
558 surf->level[level].nblk_y = ALIGN(surf->level[level].nblk_y, mtileh);
559 surf->level[level].nblk_z = ALIGN(surf->level[level].nblk_z, 1);
561 /* macro tile per row */
562 mtile_pr = surf->level[level].nblk_x / mtilew;
563 /* macro tile per slice */
564 mtile_ps = (mtile_pr * surf->level[level].nblk_y) / mtileh;
566 surf->level[level].offset = offset;
567 surf->level[level].pitch_bytes = surf->level[level].nblk_x * surf->bpe * slice_pt;
568 surf->level[level].slice_size = mtile_ps * mtileb * slice_pt;
570 surf->bo_size = offset + surf->level[level].slice_size * surf->level[level].nblk_z * surf->array_size;
571 }
573 static int eg_surface_init_1d(struct radeon_surface_manager *surf_man,
574 struct radeon_surface *surf,
575 uint64_t offset, unsigned start_level)
576 {
577 uint32_t xalign, yalign, zalign, tilew;
578 unsigned i;
580 /* compute alignment */
581 tilew = 8;
582 xalign = surf_man->hw_info.group_bytes / (tilew * surf->bpe * surf->nsamples);
583 if (surf->flags & RADEON_SURF_SBUFFER) {
584 xalign = surf_man->hw_info.group_bytes / (tilew * surf->nsamples);
585 }
586 xalign = MAX2(tilew, xalign);
587 yalign = tilew;
588 zalign = 1;
589 if (surf->flags & RADEON_SURF_SCANOUT) {
590 xalign = MAX2((surf->bpe == 1) ? 64 : 32, xalign);
591 }
592 if (!start_level) {
593 surf->bo_alignment = MAX2(256, surf_man->hw_info.group_bytes);
594 }
596 /* build mipmap tree */
597 for (i = start_level; i <= surf->last_level; i++) {
598 surf->level[i].mode = RADEON_SURF_MODE_1D;
599 surf_minify(surf, i, xalign, yalign, zalign, offset);
600 /* level0 and first mipmap need to have alignment */
601 offset = surf->bo_size;
602 if ((i == 0)) {
603 offset = ALIGN(offset, surf->bo_alignment);
604 }
605 }
607 /* The depth and stencil buffers are in separate resources on evergreen.
608 * We allocate them in one buffer next to each other to simplify
609 * communication between the DDX and the Mesa driver. */
610 if ((surf->flags & (RADEON_SURF_ZBUFFER | RADEON_SURF_SBUFFER)) ==
611 (RADEON_SURF_ZBUFFER | RADEON_SURF_SBUFFER)) {
612 surf->stencil_offset = ALIGN(surf->bo_size, surf->bo_alignment);
613 surf->bo_size = surf->stencil_offset + surf->bo_size / 4;
614 }
616 return 0;
617 }
619 static int eg_surface_init_2d(struct radeon_surface_manager *surf_man,
620 struct radeon_surface *surf,
621 uint64_t offset, unsigned start_level)
622 {
623 unsigned tilew, tileh, tileb;
624 unsigned mtilew, mtileh, mtileb;
625 unsigned slice_pt;
626 unsigned i;
628 /* compute tile values */
629 tilew = 8;
630 tileh = 8;
631 tileb = tilew * tileh * surf->bpe * surf->nsamples;
632 /* slices per tile */
633 slice_pt = 1;
634 if (tileb > surf->tile_split) {
635 slice_pt = tileb / surf->tile_split;
636 }
637 tileb = tileb / slice_pt;
639 /* macro tile width & height */
640 mtilew = (tilew * surf->bankw * surf_man->hw_info.num_pipes) * surf->mtilea;
641 mtileh = (tileh * surf->bankh * surf_man->hw_info.num_banks) / surf->mtilea;
642 /* macro tile bytes */
643 mtileb = (mtilew / tilew) * (mtileh / tileh) * tileb;
645 if (!start_level) {
646 surf->bo_alignment = MAX2(256, mtileb);
647 }
649 /* build mipmap tree */
650 for (i = start_level; i <= surf->last_level; i++) {
651 surf->level[i].mode = RADEON_SURF_MODE_2D;
652 eg_surf_minify(surf, i, slice_pt, mtilew, mtileh, mtileb, offset);
653 if (surf->level[i].mode == RADEON_SURF_MODE_1D) {
654 return eg_surface_init_1d(surf_man, surf, offset, i);
655 }
656 /* level0 and first mipmap need to have alignment */
657 offset = surf->bo_size;
658 if ((i == 0)) {
659 offset = ALIGN(offset, surf->bo_alignment);
660 }
661 }
663 if ((surf->flags & (RADEON_SURF_ZBUFFER | RADEON_SURF_SBUFFER)) ==
664 (RADEON_SURF_ZBUFFER | RADEON_SURF_SBUFFER)) {
665 surf->stencil_offset = ALIGN(surf->bo_size, surf->bo_alignment);
666 surf->bo_size = surf->stencil_offset + surf->bo_size / 4;
667 }
669 return 0;
670 }
672 static int eg_surface_sanity(struct radeon_surface_manager *surf_man,
673 struct radeon_surface *surf,
674 unsigned mode)
675 {
676 unsigned tileb;
678 /* check surface dimension */
679 if (surf->npix_x > 16384 || surf->npix_y > 16384 || surf->npix_z > 16384) {
680 return -EINVAL;
681 }
683 /* check mipmap last_level */
684 if (surf->last_level > 15) {
685 return -EINVAL;
686 }
688 /* force 1d on kernel that can't do 2d */
689 if (!surf_man->hw_info.allow_2d && mode > RADEON_SURF_MODE_1D) {
690 mode = RADEON_SURF_MODE_1D;
691 surf->flags = RADEON_SURF_CLR(surf->flags, MODE);
692 surf->flags |= RADEON_SURF_SET(mode, MODE);
693 }
695 /* check tile split */
696 if (mode == RADEON_SURF_MODE_2D) {
697 switch (surf->tile_split) {
698 case 64:
699 case 128:
700 case 256:
701 case 512:
702 case 1024:
703 case 2048:
704 case 4096:
705 break;
706 default:
707 return -EINVAL;
708 }
709 switch (surf->mtilea) {
710 case 1:
711 case 2:
712 case 4:
713 case 8:
714 break;
715 default:
716 return -EINVAL;
717 }
718 /* check aspect ratio */
719 if (surf_man->hw_info.num_banks < surf->mtilea) {
720 return -EINVAL;
721 }
722 /* check bank width */
723 switch (surf->bankw) {
724 case 1:
725 case 2:
726 case 4:
727 case 8:
728 break;
729 default:
730 return -EINVAL;
731 }
732 /* check bank height */
733 switch (surf->bankh) {
734 case 1:
735 case 2:
736 case 4:
737 case 8:
738 break;
739 default:
740 return -EINVAL;
741 }
742 tileb = MIN2(surf->tile_split, 64 * surf->bpe * surf->nsamples);
743 if ((tileb * surf->bankh * surf->bankw) < surf_man->hw_info.group_bytes) {
744 return -EINVAL;
745 }
746 }
748 return 0;
749 }
751 static int eg_surface_init(struct radeon_surface_manager *surf_man,
752 struct radeon_surface *surf)
753 {
754 unsigned mode;
755 int r;
757 /* tiling mode */
758 mode = (surf->flags >> RADEON_SURF_MODE_SHIFT) & RADEON_SURF_MODE_MASK;
760 if (surf->flags & (RADEON_SURF_ZBUFFER | RADEON_SURF_SBUFFER)) {
761 /* zbuffer only support 1D or 2D tiled surface */
762 switch (mode) {
763 case RADEON_SURF_MODE_1D:
764 case RADEON_SURF_MODE_2D:
765 break;
766 default:
767 mode = RADEON_SURF_MODE_1D;
768 surf->flags = RADEON_SURF_CLR(surf->flags, MODE);
769 surf->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_1D, MODE);
770 break;
771 }
772 }
774 r = eg_surface_sanity(surf_man, surf, mode);
775 if (r) {
776 return r;
777 }
779 surf->stencil_offset = 0;
780 surf->stencil_tile_split = 0;
782 /* check tiling mode */
783 switch (mode) {
784 case RADEON_SURF_MODE_LINEAR:
785 r = r6_surface_init_linear(surf_man, surf, 0, 0);
786 break;
787 case RADEON_SURF_MODE_LINEAR_ALIGNED:
788 r = r6_surface_init_linear_aligned(surf_man, surf, 0, 0);
789 break;
790 case RADEON_SURF_MODE_1D:
791 r = eg_surface_init_1d(surf_man, surf, 0, 0);
792 break;
793 case RADEON_SURF_MODE_2D:
794 r = eg_surface_init_2d(surf_man, surf, 0, 0);
795 break;
796 default:
797 return -EINVAL;
798 }
799 return r;
800 }
802 static unsigned log2_int(unsigned x)
803 {
804 unsigned l;
806 if (x < 2) {
807 return 0;
808 }
809 for (l = 2; ; l++) {
810 if ((unsigned)(1 << l) > x) {
811 return l - 1;
812 }
813 }
814 return 0;
815 }
817 /* compute best tile_split, bankw, bankh, mtilea
818 * depending on surface
819 */
820 static int eg_surface_best(struct radeon_surface_manager *surf_man,
821 struct radeon_surface *surf)
822 {
823 unsigned mode, tileb, h_over_w;
824 int r;
826 /* tiling mode */
827 mode = (surf->flags >> RADEON_SURF_MODE_SHIFT) & RADEON_SURF_MODE_MASK;
829 /* set some default value to avoid sanity check choking on them */
830 surf->tile_split = 1024;
831 surf->bankw = 1;
832 surf->bankh = 1;
833 surf->mtilea = surf_man->hw_info.num_banks;
834 tileb = MIN2(surf->tile_split, 64 * surf->bpe * surf->nsamples);
835 for (; surf->bankh <= 8; surf->bankh *= 2) {
836 if ((tileb * surf->bankh * surf->bankw) >= surf_man->hw_info.group_bytes) {
837 break;
838 }
839 }
840 if (surf->mtilea > 8) {
841 surf->mtilea = 8;
842 }
844 r = eg_surface_sanity(surf_man, surf, mode);
845 if (r) {
846 return r;
847 }
849 if (mode != RADEON_SURF_MODE_2D) {
850 /* nothing to do for non 2D tiled surface */
851 return 0;
852 }
854 /* set tile split to row size, optimize latter for multi-sample surface
855 * tile split >= 256 for render buffer surface. Also depth surface want
856 * smaller value for optimal performances.
857 */
858 surf->tile_split = surf_man->hw_info.row_size;
859 surf->stencil_tile_split = surf_man->hw_info.row_size / 2;
861 /* bankw or bankh greater than 1 increase alignment requirement, not
862 * sure if it's worth using smaller bankw & bankh to stick with 2D
863 * tiling on small surface rather than falling back to 1D tiling.
864 * Use recommanded value based on tile size for now.
865 *
866 * fmask buffer has different optimal value figure them out once we
867 * use it.
868 */
869 if (surf->flags & (RADEON_SURF_ZBUFFER | RADEON_SURF_SBUFFER)) {
870 /* assume 1 bytes for stencil, we optimize for stencil as stencil
871 * and depth shares surface values
872 */
873 tileb = MIN2(surf->tile_split, 64 * surf->nsamples);
874 } else {
875 tileb = MIN2(surf->tile_split, 64 * surf->bpe * surf->nsamples);
876 }
878 /* use bankw of 1 to minimize width alignment, might be interesting to
879 * increase it for large surface
880 */
881 surf->bankw = 1;
882 switch (tileb) {
883 case 64:
884 surf->bankh = 4;
885 break;
886 case 128:
887 case 256:
888 surf->bankh = 2;
889 break;
890 default:
891 surf->bankh = 1;
892 break;
893 }
894 /* double check the constraint */
895 for (; surf->bankh <= 8; surf->bankh *= 2) {
896 if ((tileb * surf->bankh * surf->bankw) >= surf_man->hw_info.group_bytes) {
897 break;
898 }
899 }
901 h_over_w = (((surf->bankh * surf_man->hw_info.num_banks) << 16) /
902 (surf->bankw * surf_man->hw_info.num_pipes)) >> 16;
903 surf->mtilea = 1 << (log2_int(h_over_w) >> 1);
905 return 0;
906 }
909 /* ===========================================================================
910 * public API
911 */
912 struct radeon_surface_manager *radeon_surface_manager_new(int fd)
913 {
914 struct radeon_surface_manager *surf_man;
916 surf_man = calloc(1, sizeof(struct radeon_surface_manager));
917 if (surf_man == NULL) {
918 return NULL;
919 }
920 surf_man->fd = fd;
921 if (radeon_get_value(fd, RADEON_INFO_DEVICE_ID, &surf_man->device_id)) {
922 goto out_err;
923 }
924 if (radeon_get_family(surf_man)) {
925 goto out_err;
926 }
928 if (surf_man->family <= CHIP_RV740) {
929 if (r6_init_hw_info(surf_man)) {
930 goto out_err;
931 }
932 surf_man->surface_init = &r6_surface_init;
933 surf_man->surface_best = &r6_surface_best;
934 } else {
935 if (eg_init_hw_info(surf_man)) {
936 goto out_err;
937 }
938 surf_man->surface_init = &eg_surface_init;
939 surf_man->surface_best = &eg_surface_best;
940 }
942 return surf_man;
943 out_err:
944 free(surf_man);
945 return NULL;
946 }
948 void radeon_surface_manager_free(struct radeon_surface_manager *surf_man)
949 {
950 free(surf_man);
951 }
953 static int radeon_surface_sanity(struct radeon_surface_manager *surf_man,
954 struct radeon_surface *surf,
955 unsigned type,
956 unsigned mode)
957 {
958 if (surf_man == NULL || surf_man->surface_init == NULL || surf == NULL) {
959 return -EINVAL;
960 }
962 /* all dimension must be at least 1 ! */
963 if (!surf->npix_x || !surf->npix_y || !surf->npix_z) {
964 return -EINVAL;
965 }
966 if (!surf->blk_w || !surf->blk_h || !surf->blk_d) {
967 return -EINVAL;
968 }
969 if (!surf->array_size) {
970 return -EINVAL;
971 }
972 /* array size must be a power of 2 */
973 surf->array_size = next_power_of_two(surf->array_size);
975 switch (surf->nsamples) {
976 case 1:
977 case 2:
978 case 4:
979 case 8:
980 break;
981 default:
982 return -EINVAL;
983 }
984 /* check type */
985 switch (type) {
986 case RADEON_SURF_TYPE_1D:
987 if (surf->npix_y > 1) {
988 return -EINVAL;
989 }
990 case RADEON_SURF_TYPE_2D:
991 if (surf->npix_z > 1) {
992 return -EINVAL;
993 }
994 break;
995 case RADEON_SURF_TYPE_CUBEMAP:
996 if (surf->npix_z > 1) {
997 return -EINVAL;
998 }
999 /* deal with cubemap as they were texture array */
1000 if (surf_man->family >= CHIP_RV770) {
1001 surf->array_size = 8;
1002 } else {
1003 surf->array_size = 6;
1004 }
1005 break;
1006 case RADEON_SURF_TYPE_3D:
1007 break;
1008 case RADEON_SURF_TYPE_1D_ARRAY:
1009 if (surf->npix_y > 1) {
1010 return -EINVAL;
1011 }
1012 case RADEON_SURF_TYPE_2D_ARRAY:
1013 break;
1014 default:
1015 return -EINVAL;
1016 }
1017 return 0;
1018 }
1020 int radeon_surface_init(struct radeon_surface_manager *surf_man,
1021 struct radeon_surface *surf)
1022 {
1023 unsigned mode, type;
1024 int r;
1026 type = RADEON_SURF_GET(surf->flags, TYPE);
1027 mode = RADEON_SURF_GET(surf->flags, MODE);
1029 r = radeon_surface_sanity(surf_man, surf, type, mode);
1030 if (r) {
1031 return r;
1032 }
1033 return surf_man->surface_init(surf_man, surf);
1034 }
1036 int radeon_surface_best(struct radeon_surface_manager *surf_man,
1037 struct radeon_surface *surf)
1038 {
1039 unsigned mode, type;
1040 int r;
1042 type = RADEON_SURF_GET(surf->flags, TYPE);
1043 mode = RADEON_SURF_GET(surf->flags, MODE);
1045 r = radeon_surface_sanity(surf_man, surf, type, mode);
1046 if (r) {
1047 return r;
1048 }
1049 return surf_man->surface_best(surf_man, surf);
1050 }