2 * Copyright © 2011 Red Hat All Rights Reserved.
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:
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.
21 * The above copyright notice and this permission notice (including the
22 * next paragraph) shall be included in all copies or substantial portions
27 * Jérôme Glisse <jglisse@redhat.com>
34 #include <sys/ioctl.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 */
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 {
93 struct radeon_surface_manager {
96 struct radeon_hw_info hw_info;
98 hw_init_surface_t surface_init;
99 hw_best_surface_t surface_best;
103 static int radeon_get_value(int fd, unsigned req, uint32_t *value)
105 struct drm_radeon_info info = {};
110 info.value = (uintptr_t)value;
111 r = drmCommandWriteRead(fd, DRM_RADEON_INFO, &info,
112 sizeof(struct drm_radeon_info));
116 static int radeon_get_family(struct radeon_surface_manager *surf_man)
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"
128 static unsigned next_power_of_two(unsigned x)
133 return (1 << ((sizeof(unsigned) * 8) - __builtin_clz(x - 1)));
136 static unsigned mip_minify(unsigned size, unsigned level)
140 val = MAX2(1, size >> level);
142 val = next_power_of_two(val);
146 static void surf_minify(struct radeon_surface *surf,
147 struct radeon_surface_level *surflevel,
148 unsigned bpe, unsigned level,
149 uint32_t xalign, uint32_t yalign, uint32_t zalign,
152 surflevel->npix_x = mip_minify(surf->npix_x, level);
153 surflevel->npix_y = mip_minify(surf->npix_y, level);
154 surflevel->npix_z = mip_minify(surf->npix_z, level);
155 surflevel->nblk_x = (surflevel->npix_x + surf->blk_w - 1) / surf->blk_w;
156 surflevel->nblk_y = (surflevel->npix_y + surf->blk_h - 1) / surf->blk_h;
157 surflevel->nblk_z = (surflevel->npix_z + surf->blk_d - 1) / surf->blk_d;
158 if (surf->nsamples == 1 && surflevel->mode == RADEON_SURF_MODE_2D) {
159 if (surflevel->nblk_x < xalign || surflevel->nblk_y < yalign) {
160 surflevel->mode = RADEON_SURF_MODE_1D;
164 surflevel->nblk_x = ALIGN(surflevel->nblk_x, xalign);
165 surflevel->nblk_y = ALIGN(surflevel->nblk_y, yalign);
166 surflevel->nblk_z = ALIGN(surflevel->nblk_z, zalign);
168 surflevel->offset = offset;
169 surflevel->pitch_bytes = surflevel->nblk_x * bpe * surf->nsamples;
170 surflevel->slice_size = surflevel->pitch_bytes * surflevel->nblk_y;
172 surf->bo_size = offset + surflevel->slice_size * surflevel->nblk_z * surf->array_size;
175 /* ===========================================================================
178 static int r6_init_hw_info(struct radeon_surface_manager *surf_man)
180 uint32_t tiling_config;
181 drmVersionPtr version;
184 r = radeon_get_value(surf_man->fd, RADEON_INFO_TILING_CONFIG,
190 surf_man->hw_info.allow_2d = 0;
191 version = drmGetVersion(surf_man->fd);
192 if (version && version->version_minor >= 14) {
193 surf_man->hw_info.allow_2d = 1;
195 drmFreeVersion(version);
197 switch ((tiling_config & 0xe) >> 1) {
199 surf_man->hw_info.num_pipes = 1;
202 surf_man->hw_info.num_pipes = 2;
205 surf_man->hw_info.num_pipes = 4;
208 surf_man->hw_info.num_pipes = 8;
211 surf_man->hw_info.num_pipes = 8;
212 surf_man->hw_info.allow_2d = 0;
216 switch ((tiling_config & 0x30) >> 4) {
218 surf_man->hw_info.num_banks = 4;
221 surf_man->hw_info.num_banks = 8;
224 surf_man->hw_info.num_banks = 8;
225 surf_man->hw_info.allow_2d = 0;
229 switch ((tiling_config & 0xc0) >> 6) {
231 surf_man->hw_info.group_bytes = 256;
234 surf_man->hw_info.group_bytes = 512;
237 surf_man->hw_info.group_bytes = 256;
238 surf_man->hw_info.allow_2d = 0;
244 static int r6_surface_init_linear(struct radeon_surface_manager *surf_man,
245 struct radeon_surface *surf,
246 uint64_t offset, unsigned start_level)
248 uint32_t xalign, yalign, zalign;
251 /* compute alignment */
253 surf->bo_alignment = MAX2(256, surf_man->hw_info.group_bytes);
255 /* the 32 alignment is for scanout, cb or db but to allow texture to be
256 * easily bound as such we force this alignment to all surface
258 xalign = MAX2(1, surf_man->hw_info.group_bytes / surf->bpe);
261 if (surf->flags & RADEON_SURF_SCANOUT) {
262 xalign = MAX2((surf->bpe == 1) ? 64 : 32, xalign);
265 /* build mipmap tree */
266 for (i = start_level; i <= surf->last_level; i++) {
267 surf->level[i].mode = RADEON_SURF_MODE_LINEAR;
268 surf_minify(surf, surf->level+i, surf->bpe, i, xalign, yalign, zalign, offset);
269 /* level0 and first mipmap need to have alignment */
270 offset = surf->bo_size;
272 offset = ALIGN(offset, surf->bo_alignment);
278 static int r6_surface_init_linear_aligned(struct radeon_surface_manager *surf_man,
279 struct radeon_surface *surf,
280 uint64_t offset, unsigned start_level)
282 uint32_t xalign, yalign, zalign;
285 /* compute alignment */
287 surf->bo_alignment = MAX2(256, surf_man->hw_info.group_bytes);
289 xalign = MAX2(64, surf_man->hw_info.group_bytes / surf->bpe);
293 /* build mipmap tree */
294 for (i = start_level; i <= surf->last_level; i++) {
295 surf->level[i].mode = RADEON_SURF_MODE_LINEAR_ALIGNED;
296 surf_minify(surf, surf->level+i, surf->bpe, i, xalign, yalign, zalign, offset);
297 /* level0 and first mipmap need to have alignment */
298 offset = surf->bo_size;
300 offset = ALIGN(offset, surf->bo_alignment);
306 static int r6_surface_init_1d(struct radeon_surface_manager *surf_man,
307 struct radeon_surface *surf,
308 uint64_t offset, unsigned start_level)
310 uint32_t xalign, yalign, zalign, tilew;
313 /* compute alignment */
315 xalign = surf_man->hw_info.group_bytes / (tilew * surf->bpe * surf->nsamples);
316 xalign = MAX2(tilew, xalign);
319 if (surf->flags & RADEON_SURF_SCANOUT) {
320 xalign = MAX2((surf->bpe == 1) ? 64 : 32, xalign);
323 surf->bo_alignment = MAX2(256, surf_man->hw_info.group_bytes);
326 /* build mipmap tree */
327 for (i = start_level; i <= surf->last_level; i++) {
328 surf->level[i].mode = RADEON_SURF_MODE_1D;
329 surf_minify(surf, surf->level+i, surf->bpe, i, xalign, yalign, zalign, offset);
330 /* level0 and first mipmap need to have alignment */
331 offset = surf->bo_size;
333 offset = ALIGN(offset, surf->bo_alignment);
339 static int r6_surface_init_2d(struct radeon_surface_manager *surf_man,
340 struct radeon_surface *surf,
341 uint64_t offset, unsigned start_level)
343 uint32_t xalign, yalign, zalign, tilew;
346 /* compute alignment */
349 xalign = (surf_man->hw_info.group_bytes * surf_man->hw_info.num_banks) /
350 (tilew * surf->bpe * surf->nsamples);
351 xalign = MAX2(tilew * surf_man->hw_info.num_banks, xalign);
352 yalign = tilew * surf_man->hw_info.num_pipes;
353 if (surf->flags & RADEON_SURF_SCANOUT) {
354 xalign = MAX2((surf->bpe == 1) ? 64 : 32, xalign);
358 MAX2(surf_man->hw_info.num_pipes *
359 surf_man->hw_info.num_banks *
360 surf->nsamples * surf->bpe * 64,
361 xalign * yalign * surf->nsamples * surf->bpe);
364 /* build mipmap tree */
365 for (i = start_level; i <= surf->last_level; i++) {
366 surf->level[i].mode = RADEON_SURF_MODE_2D;
367 surf_minify(surf, surf->level+i, surf->bpe, i, xalign, yalign, zalign, offset);
368 if (surf->level[i].mode == RADEON_SURF_MODE_1D) {
369 return r6_surface_init_1d(surf_man, surf, offset, i);
371 /* level0 and first mipmap need to have alignment */
372 offset = surf->bo_size;
374 offset = ALIGN(offset, surf->bo_alignment);
380 static int r6_surface_init(struct radeon_surface_manager *surf_man,
381 struct radeon_surface *surf)
386 /* MSAA surfaces support the 2D mode only. */
387 if (surf->nsamples > 1) {
388 surf->flags = RADEON_SURF_CLR(surf->flags, MODE);
389 surf->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_2D, MODE);
393 mode = (surf->flags >> RADEON_SURF_MODE_SHIFT) & RADEON_SURF_MODE_MASK;
395 if (surf->flags & (RADEON_SURF_ZBUFFER | RADEON_SURF_SBUFFER)) {
396 /* zbuffer only support 1D or 2D tiled surface */
398 case RADEON_SURF_MODE_1D:
399 case RADEON_SURF_MODE_2D:
402 mode = RADEON_SURF_MODE_1D;
403 surf->flags = RADEON_SURF_CLR(surf->flags, MODE);
404 surf->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_1D, MODE);
409 /* force 1d on kernel that can't do 2d */
410 if (!surf_man->hw_info.allow_2d && mode > RADEON_SURF_MODE_1D) {
411 if (surf->nsamples > 1) {
412 fprintf(stderr, "radeon: Cannot use 2D tiling for an MSAA surface (%i).\n", __LINE__);
415 mode = RADEON_SURF_MODE_1D;
416 surf->flags = RADEON_SURF_CLR(surf->flags, MODE);
417 surf->flags |= RADEON_SURF_SET(mode, MODE);
420 /* check surface dimension */
421 if (surf->npix_x > 8192 || surf->npix_y > 8192 || surf->npix_z > 8192) {
425 /* check mipmap last_level */
426 if (surf->last_level > 14) {
430 /* check tiling mode */
432 case RADEON_SURF_MODE_LINEAR:
433 r = r6_surface_init_linear(surf_man, surf, 0, 0);
435 case RADEON_SURF_MODE_LINEAR_ALIGNED:
436 r = r6_surface_init_linear_aligned(surf_man, surf, 0, 0);
438 case RADEON_SURF_MODE_1D:
439 r = r6_surface_init_1d(surf_man, surf, 0, 0);
441 case RADEON_SURF_MODE_2D:
442 r = r6_surface_init_2d(surf_man, surf, 0, 0);
450 static int r6_surface_best(struct radeon_surface_manager *surf_man,
451 struct radeon_surface *surf)
453 /* no value to optimize for r6xx/r7xx */
458 /* ===========================================================================
461 static int eg_init_hw_info(struct radeon_surface_manager *surf_man)
463 uint32_t tiling_config;
464 drmVersionPtr version;
467 r = radeon_get_value(surf_man->fd, RADEON_INFO_TILING_CONFIG,
473 surf_man->hw_info.allow_2d = 0;
474 version = drmGetVersion(surf_man->fd);
475 if (version && version->version_minor >= 16) {
476 surf_man->hw_info.allow_2d = 1;
478 drmFreeVersion(version);
480 switch (tiling_config & 0xf) {
482 surf_man->hw_info.num_pipes = 1;
485 surf_man->hw_info.num_pipes = 2;
488 surf_man->hw_info.num_pipes = 4;
491 surf_man->hw_info.num_pipes = 8;
494 surf_man->hw_info.num_pipes = 8;
495 surf_man->hw_info.allow_2d = 0;
499 switch ((tiling_config & 0xf0) >> 4) {
501 surf_man->hw_info.num_banks = 4;
504 surf_man->hw_info.num_banks = 8;
507 surf_man->hw_info.num_banks = 16;
510 surf_man->hw_info.num_banks = 8;
511 surf_man->hw_info.allow_2d = 0;
515 switch ((tiling_config & 0xf00) >> 8) {
517 surf_man->hw_info.group_bytes = 256;
520 surf_man->hw_info.group_bytes = 512;
523 surf_man->hw_info.group_bytes = 256;
524 surf_man->hw_info.allow_2d = 0;
528 switch ((tiling_config & 0xf000) >> 12) {
530 surf_man->hw_info.row_size = 1024;
533 surf_man->hw_info.row_size = 2048;
536 surf_man->hw_info.row_size = 4096;
539 surf_man->hw_info.row_size = 4096;
540 surf_man->hw_info.allow_2d = 0;
546 static void eg_surf_minify(struct radeon_surface *surf,
547 struct radeon_surface_level *surflevel,
556 unsigned mtile_pr, mtile_ps;
558 surflevel->npix_x = mip_minify(surf->npix_x, level);
559 surflevel->npix_y = mip_minify(surf->npix_y, level);
560 surflevel->npix_z = mip_minify(surf->npix_z, level);
561 surflevel->nblk_x = (surflevel->npix_x + surf->blk_w - 1) / surf->blk_w;
562 surflevel->nblk_y = (surflevel->npix_y + surf->blk_h - 1) / surf->blk_h;
563 surflevel->nblk_z = (surflevel->npix_z + surf->blk_d - 1) / surf->blk_d;
564 if (surf->nsamples == 1 && surflevel->mode == RADEON_SURF_MODE_2D) {
565 if (surflevel->nblk_x < mtilew || surflevel->nblk_y < mtileh) {
566 surflevel->mode = RADEON_SURF_MODE_1D;
570 surflevel->nblk_x = ALIGN(surflevel->nblk_x, mtilew);
571 surflevel->nblk_y = ALIGN(surflevel->nblk_y, mtileh);
572 surflevel->nblk_z = ALIGN(surflevel->nblk_z, 1);
574 /* macro tile per row */
575 mtile_pr = surflevel->nblk_x / mtilew;
576 /* macro tile per slice */
577 mtile_ps = (mtile_pr * surflevel->nblk_y) / mtileh;
579 surflevel->offset = offset;
580 surflevel->pitch_bytes = surflevel->nblk_x * bpe * slice_pt;
581 surflevel->slice_size = mtile_ps * mtileb * slice_pt;
583 surf->bo_size = offset + surflevel->slice_size * surflevel->nblk_z * surf->array_size;
586 static int eg_surface_init_1d(struct radeon_surface_manager *surf_man,
587 struct radeon_surface *surf,
588 struct radeon_surface_level *level,
590 uint64_t offset, unsigned start_level)
592 uint32_t xalign, yalign, zalign, tilew;
595 /* compute alignment */
597 xalign = surf_man->hw_info.group_bytes / (tilew * bpe * surf->nsamples);
598 xalign = MAX2(tilew, xalign);
601 if (surf->flags & RADEON_SURF_SCANOUT) {
602 xalign = MAX2((bpe == 1) ? 64 : 32, xalign);
606 unsigned alignment = MAX2(256, surf_man->hw_info.group_bytes);
607 surf->bo_alignment = MAX2(surf->bo_alignment, alignment);
610 offset = ALIGN(offset, alignment);
614 /* build mipmap tree */
615 for (i = start_level; i <= surf->last_level; i++) {
616 level[i].mode = RADEON_SURF_MODE_1D;
617 surf_minify(surf, level+i, bpe, i, xalign, yalign, zalign, offset);
618 /* level0 and first mipmap need to have alignment */
619 offset = surf->bo_size;
621 offset = ALIGN(offset, surf->bo_alignment);
627 static int eg_surface_init_2d(struct radeon_surface_manager *surf_man,
628 struct radeon_surface *surf,
629 struct radeon_surface_level *level,
630 unsigned bpe, unsigned tile_split,
631 uint64_t offset, unsigned start_level)
633 unsigned tilew, tileh, tileb;
634 unsigned mtilew, mtileh, mtileb;
638 /* compute tile values */
641 tileb = tilew * tileh * bpe * surf->nsamples;
642 /* slices per tile */
644 if (tileb > tile_split) {
645 slice_pt = tileb / tile_split;
647 tileb = tileb / slice_pt;
649 /* macro tile width & height */
650 mtilew = (tilew * surf->bankw * surf_man->hw_info.num_pipes) * surf->mtilea;
651 mtileh = (tileh * surf->bankh * surf_man->hw_info.num_banks) / surf->mtilea;
652 /* macro tile bytes */
653 mtileb = (mtilew / tilew) * (mtileh / tileh) * tileb;
656 unsigned alignment = MAX2(256, mtileb);
657 surf->bo_alignment = MAX2(surf->bo_alignment, alignment);
660 offset = ALIGN(offset, alignment);
664 /* build mipmap tree */
665 for (i = start_level; i <= surf->last_level; i++) {
666 level[i].mode = RADEON_SURF_MODE_2D;
667 eg_surf_minify(surf, level+i, bpe, i, slice_pt, mtilew, mtileh, mtileb, offset);
668 if (level[i].mode == RADEON_SURF_MODE_1D) {
669 return eg_surface_init_1d(surf_man, surf, level, bpe, offset, i);
671 /* level0 and first mipmap need to have alignment */
672 offset = surf->bo_size;
674 offset = ALIGN(offset, surf->bo_alignment);
680 static int eg_surface_sanity(struct radeon_surface_manager *surf_man,
681 struct radeon_surface *surf,
686 /* check surface dimension */
687 if (surf->npix_x > 16384 || surf->npix_y > 16384 || surf->npix_z > 16384) {
691 /* check mipmap last_level */
692 if (surf->last_level > 15) {
696 /* force 1d on kernel that can't do 2d */
697 if (!surf_man->hw_info.allow_2d && mode > RADEON_SURF_MODE_1D) {
698 if (surf->nsamples > 1) {
699 fprintf(stderr, "radeon: Cannot use 2D tiling for an MSAA surface (%i).\n", __LINE__);
702 mode = RADEON_SURF_MODE_1D;
703 surf->flags = RADEON_SURF_CLR(surf->flags, MODE);
704 surf->flags |= RADEON_SURF_SET(mode, MODE);
707 /* check tile split */
708 if (mode == RADEON_SURF_MODE_2D) {
709 switch (surf->tile_split) {
721 switch (surf->mtilea) {
730 /* check aspect ratio */
731 if (surf_man->hw_info.num_banks < surf->mtilea) {
734 /* check bank width */
735 switch (surf->bankw) {
744 /* check bank height */
745 switch (surf->bankh) {
754 tileb = MIN2(surf->tile_split, 64 * surf->bpe * surf->nsamples);
755 if ((tileb * surf->bankh * surf->bankw) < surf_man->hw_info.group_bytes) {
763 static int eg_surface_init_1d_miptrees(struct radeon_surface_manager *surf_man,
764 struct radeon_surface *surf)
766 unsigned zs_flags = RADEON_SURF_ZBUFFER | RADEON_SURF_SBUFFER;
767 int r, is_depth_stencil = (surf->flags & zs_flags) == zs_flags;
768 /* Old libdrm headers didn't have stencil_level in it. This prevents crashes. */
769 struct radeon_surface_level tmp[RADEON_SURF_MAX_LEVEL];
770 struct radeon_surface_level *stencil_level =
771 (surf->flags & RADEON_SURF_HAS_SBUFFER_MIPTREE) ? surf->stencil_level : tmp;
773 r = eg_surface_init_1d(surf_man, surf, surf->level, surf->bpe, 0, 0);
777 if (is_depth_stencil) {
778 r = eg_surface_init_1d(surf_man, surf, stencil_level, 1,
780 surf->stencil_offset = stencil_level[0].offset;
785 static int eg_surface_init_2d_miptrees(struct radeon_surface_manager *surf_man,
786 struct radeon_surface *surf)
788 unsigned zs_flags = RADEON_SURF_ZBUFFER | RADEON_SURF_SBUFFER;
789 int r, is_depth_stencil = (surf->flags & zs_flags) == zs_flags;
790 /* Old libdrm headers didn't have stencil_level in it. This prevents crashes. */
791 struct radeon_surface_level tmp[RADEON_SURF_MAX_LEVEL];
792 struct radeon_surface_level *stencil_level =
793 (surf->flags & RADEON_SURF_HAS_SBUFFER_MIPTREE) ? surf->stencil_level : tmp;
795 r = eg_surface_init_2d(surf_man, surf, surf->level, surf->bpe,
796 surf->tile_split, 0, 0);
800 if (is_depth_stencil) {
801 r = eg_surface_init_2d(surf_man, surf, stencil_level, 1,
802 surf->stencil_tile_split, surf->bo_size, 0);
803 surf->stencil_offset = stencil_level[0].offset;
808 static int eg_surface_init(struct radeon_surface_manager *surf_man,
809 struct radeon_surface *surf)
814 /* MSAA surfaces support the 2D mode only. */
815 if (surf->nsamples > 1) {
816 surf->flags = RADEON_SURF_CLR(surf->flags, MODE);
817 surf->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_2D, MODE);
821 mode = (surf->flags >> RADEON_SURF_MODE_SHIFT) & RADEON_SURF_MODE_MASK;
823 if (surf->flags & (RADEON_SURF_ZBUFFER | RADEON_SURF_SBUFFER)) {
824 /* zbuffer only support 1D or 2D tiled surface */
826 case RADEON_SURF_MODE_1D:
827 case RADEON_SURF_MODE_2D:
830 mode = RADEON_SURF_MODE_1D;
831 surf->flags = RADEON_SURF_CLR(surf->flags, MODE);
832 surf->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_1D, MODE);
837 r = eg_surface_sanity(surf_man, surf, mode);
842 surf->stencil_offset = 0;
843 surf->bo_alignment = 0;
845 /* check tiling mode */
847 case RADEON_SURF_MODE_LINEAR:
848 r = r6_surface_init_linear(surf_man, surf, 0, 0);
850 case RADEON_SURF_MODE_LINEAR_ALIGNED:
851 r = r6_surface_init_linear_aligned(surf_man, surf, 0, 0);
853 case RADEON_SURF_MODE_1D:
854 r = eg_surface_init_1d_miptrees(surf_man, surf);
856 case RADEON_SURF_MODE_2D:
857 r = eg_surface_init_2d_miptrees(surf_man, surf);
865 static unsigned log2_int(unsigned x)
873 if ((unsigned)(1 << l) > x) {
880 /* compute best tile_split, bankw, bankh, mtilea
881 * depending on surface
883 static int eg_surface_best(struct radeon_surface_manager *surf_man,
884 struct radeon_surface *surf)
886 unsigned mode, tileb, h_over_w;
890 mode = (surf->flags >> RADEON_SURF_MODE_SHIFT) & RADEON_SURF_MODE_MASK;
892 /* set some default value to avoid sanity check choking on them */
893 surf->tile_split = 1024;
896 surf->mtilea = surf_man->hw_info.num_banks;
897 tileb = MIN2(surf->tile_split, 64 * surf->bpe * surf->nsamples);
898 for (; surf->bankh <= 8; surf->bankh *= 2) {
899 if ((tileb * surf->bankh * surf->bankw) >= surf_man->hw_info.group_bytes) {
903 if (surf->mtilea > 8) {
907 r = eg_surface_sanity(surf_man, surf, mode);
912 if (mode != RADEON_SURF_MODE_2D) {
913 /* nothing to do for non 2D tiled surface */
917 /* Tweak TILE_SPLIT for performance here. */
918 if (surf->nsamples > 1) {
919 if (surf->flags & (RADEON_SURF_ZBUFFER | RADEON_SURF_SBUFFER)) {
920 switch (surf->nsamples) {
922 surf->tile_split = 128;
925 surf->tile_split = 128;
928 surf->tile_split = 256;
930 case 16: /* cayman only */
931 surf->tile_split = 512;
934 fprintf(stderr, "radeon: Wrong number of samples %i (%i)\n",
935 surf->nsamples, __LINE__);
938 surf->stencil_tile_split = 64;
940 /* tile split must be >= 256 for colorbuffer surfaces */
941 surf->tile_split = MAX2(surf->nsamples * surf->bpe * 64, 256);
942 if (surf->tile_split > 4096)
943 surf->tile_split = 4096;
946 /* set tile split to row size */
947 surf->tile_split = surf_man->hw_info.row_size;
948 surf->stencil_tile_split = surf_man->hw_info.row_size / 2;
951 /* bankw or bankh greater than 1 increase alignment requirement, not
952 * sure if it's worth using smaller bankw & bankh to stick with 2D
953 * tiling on small surface rather than falling back to 1D tiling.
954 * Use recommanded value based on tile size for now.
956 * fmask buffer has different optimal value figure them out once we
959 if (surf->flags & RADEON_SURF_SBUFFER) {
960 /* assume 1 bytes for stencil, we optimize for stencil as stencil
961 * and depth shares surface values
963 tileb = MIN2(surf->tile_split, 64 * surf->nsamples);
965 tileb = MIN2(surf->tile_split, 64 * surf->bpe * surf->nsamples);
968 /* use bankw of 1 to minimize width alignment, might be interesting to
969 * increase it for large surface
984 /* double check the constraint */
985 for (; surf->bankh <= 8; surf->bankh *= 2) {
986 if ((tileb * surf->bankh * surf->bankw) >= surf_man->hw_info.group_bytes) {
991 h_over_w = (((surf->bankh * surf_man->hw_info.num_banks) << 16) /
992 (surf->bankw * surf_man->hw_info.num_pipes)) >> 16;
993 surf->mtilea = 1 << (log2_int(h_over_w) >> 1);
999 /* ===========================================================================
1000 * Southern Islands family
1003 static void si_surf_minify(struct radeon_surface *surf,
1004 struct radeon_surface_level *surflevel,
1005 unsigned bpe, unsigned level,
1006 uint32_t xalign, uint32_t yalign, uint32_t zalign, uint32_t slice_align,
1009 surflevel->npix_x = mip_minify(surf->npix_x, level);
1010 surflevel->npix_y = mip_minify(surf->npix_y, level);
1011 surflevel->npix_z = mip_minify(surf->npix_z, level);
1013 if (level == 0 && surf->last_level > 0) {
1014 surflevel->nblk_x = (next_power_of_two(surflevel->npix_x) + surf->blk_w - 1) / surf->blk_w;
1015 surflevel->nblk_y = (next_power_of_two(surflevel->npix_y) + surf->blk_h - 1) / surf->blk_h;
1016 surflevel->nblk_z = (next_power_of_two(surflevel->npix_z) + surf->blk_d - 1) / surf->blk_d;
1018 surflevel->nblk_x = (surflevel->npix_x + surf->blk_w - 1) / surf->blk_w;
1019 surflevel->nblk_y = (surflevel->npix_y + surf->blk_h - 1) / surf->blk_h;
1020 surflevel->nblk_z = (surflevel->npix_z + surf->blk_d - 1) / surf->blk_d;
1023 surflevel->nblk_y = ALIGN(surflevel->nblk_y, yalign);
1025 /* XXX: Texture sampling uses unexpectedly large pitches in some cases,
1026 * these are just guesses for the rules behind those
1028 if (level == 0 && surf->last_level == 0)
1029 /* Non-mipmap pitch padded to slice alignment */
1030 xalign = MAX2(xalign, slice_align / surf->bpe);
1032 /* Small rows evenly distributed across slice */
1033 xalign = MAX2(xalign, slice_align / surf->bpe / surflevel->nblk_y);
1035 surflevel->nblk_x = ALIGN(surflevel->nblk_x, xalign);
1036 surflevel->nblk_z = ALIGN(surflevel->nblk_z, zalign);
1038 surflevel->offset = offset;
1039 surflevel->pitch_bytes = surflevel->nblk_x * surf->bpe * surf->nsamples;
1040 surflevel->slice_size = ALIGN(surflevel->pitch_bytes * surflevel->nblk_y, slice_align);
1042 surf->bo_size = offset + surflevel->slice_size * surflevel->nblk_z * surf->array_size;
1045 static int si_surface_init_linear_aligned(struct radeon_surface_manager *surf_man,
1046 struct radeon_surface *surf,
1047 uint64_t offset, unsigned start_level)
1049 uint32_t xalign, yalign, zalign, slice_align;
1052 /* compute alignment */
1054 surf->bo_alignment = MAX2(256, surf_man->hw_info.group_bytes);
1056 xalign = MAX2(8, 64 / surf->bpe);
1059 slice_align = MAX2(64 * surf->bpe, surf_man->hw_info.group_bytes);
1061 /* build mipmap tree */
1062 for (i = start_level; i <= surf->last_level; i++) {
1063 surf->level[i].mode = RADEON_SURF_MODE_LINEAR_ALIGNED;
1064 si_surf_minify(surf, surf->level+i, surf->bpe, i, xalign, yalign,
1065 zalign, slice_align, offset);
1066 /* level0 and first mipmap need to have alignment */
1067 offset = surf->bo_size;
1069 offset = ALIGN(offset, surf->bo_alignment);
1075 static int si_surface_init_1d(struct radeon_surface_manager *surf_man,
1076 struct radeon_surface *surf,
1077 struct radeon_surface_level *level,
1079 uint64_t offset, unsigned start_level)
1081 uint32_t xalign, yalign, zalign, slice_align;
1084 /* compute alignment */
1088 slice_align = surf_man->hw_info.group_bytes;
1089 if (surf->flags & RADEON_SURF_SCANOUT) {
1090 xalign = MAX2((bpe == 1) ? 64 : 32, xalign);
1094 unsigned alignment = MAX2(256, surf_man->hw_info.group_bytes);
1095 surf->bo_alignment = MAX2(surf->bo_alignment, alignment);
1098 offset = ALIGN(offset, alignment);
1102 /* build mipmap tree */
1103 for (i = start_level; i <= surf->last_level; i++) {
1104 level[i].mode = RADEON_SURF_MODE_1D;
1105 si_surf_minify(surf, level+i, bpe, i, xalign, yalign, zalign, slice_align, offset);
1106 /* level0 and first mipmap need to have alignment */
1107 offset = surf->bo_size;
1109 offset = ALIGN(offset, surf->bo_alignment);
1115 static int si_surface_init_1d_miptrees(struct radeon_surface_manager *surf_man,
1116 struct radeon_surface *surf)
1118 unsigned zs_flags = RADEON_SURF_ZBUFFER | RADEON_SURF_SBUFFER;
1119 int r, is_depth_stencil = (surf->flags & zs_flags) == zs_flags;
1120 /* Old libdrm headers didn't have stencil_level in it. This prevents crashes. */
1121 struct radeon_surface_level tmp[RADEON_SURF_MAX_LEVEL];
1122 struct radeon_surface_level *stencil_level =
1123 (surf->flags & RADEON_SURF_HAS_SBUFFER_MIPTREE) ? surf->stencil_level : tmp;
1125 r = si_surface_init_1d(surf_man, surf, surf->level, surf->bpe, 0, 0);
1129 if (is_depth_stencil) {
1130 r = si_surface_init_1d(surf_man, surf, stencil_level, 1,
1132 surf->stencil_offset = stencil_level[0].offset;
1137 static int si_surface_init(struct radeon_surface_manager *surf_man,
1138 struct radeon_surface *surf)
1143 /* MSAA surfaces support the 2D mode only. */
1144 if (surf->nsamples > 1) {
1145 surf->flags = RADEON_SURF_CLR(surf->flags, MODE);
1146 surf->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_2D, MODE);
1150 mode = (surf->flags >> RADEON_SURF_MODE_SHIFT) & RADEON_SURF_MODE_MASK;
1152 if (surf->flags & (RADEON_SURF_ZBUFFER | RADEON_SURF_SBUFFER)) {
1153 /* zbuffer only support 1D or 2D tiled surface */
1155 case RADEON_SURF_MODE_1D:
1156 case RADEON_SURF_MODE_2D:
1159 mode = RADEON_SURF_MODE_1D;
1160 surf->flags = RADEON_SURF_CLR(surf->flags, MODE);
1161 surf->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_1D, MODE);
1166 r = eg_surface_sanity(surf_man, surf, mode);
1171 surf->stencil_offset = 0;
1172 surf->bo_alignment = 0;
1174 /* check tiling mode */
1176 case RADEON_SURF_MODE_LINEAR:
1177 r = r6_surface_init_linear(surf_man, surf, 0, 0);
1179 case RADEON_SURF_MODE_LINEAR_ALIGNED:
1180 r = si_surface_init_linear_aligned(surf_man, surf, 0, 0);
1182 case RADEON_SURF_MODE_1D:
1183 r = si_surface_init_1d_miptrees(surf_man, surf);
1185 case RADEON_SURF_MODE_2D:
1186 r = eg_surface_init_2d_miptrees(surf_man, surf);
1194 /* ===========================================================================
1197 struct radeon_surface_manager *radeon_surface_manager_new(int fd)
1199 struct radeon_surface_manager *surf_man;
1201 surf_man = calloc(1, sizeof(struct radeon_surface_manager));
1202 if (surf_man == NULL) {
1206 if (radeon_get_value(fd, RADEON_INFO_DEVICE_ID, &surf_man->device_id)) {
1209 if (radeon_get_family(surf_man)) {
1213 if (surf_man->family <= CHIP_RV740) {
1214 if (r6_init_hw_info(surf_man)) {
1217 surf_man->surface_init = &r6_surface_init;
1218 surf_man->surface_best = &r6_surface_best;
1220 if (eg_init_hw_info(surf_man)) {
1223 if (surf_man->family <= CHIP_ARUBA) {
1224 surf_man->surface_init = &eg_surface_init;
1226 surf_man->surface_init = &si_surface_init;
1228 surf_man->surface_best = &eg_surface_best;
1237 void radeon_surface_manager_free(struct radeon_surface_manager *surf_man)
1242 static int radeon_surface_sanity(struct radeon_surface_manager *surf_man,
1243 struct radeon_surface *surf,
1247 if (surf_man == NULL || surf_man->surface_init == NULL || surf == NULL) {
1251 /* all dimension must be at least 1 ! */
1252 if (!surf->npix_x || !surf->npix_y || !surf->npix_z) {
1255 if (!surf->blk_w || !surf->blk_h || !surf->blk_d) {
1258 if (!surf->array_size) {
1261 /* array size must be a power of 2 */
1262 surf->array_size = next_power_of_two(surf->array_size);
1264 switch (surf->nsamples) {
1275 case RADEON_SURF_TYPE_1D:
1276 if (surf->npix_y > 1) {
1279 case RADEON_SURF_TYPE_2D:
1280 if (surf->npix_z > 1) {
1284 case RADEON_SURF_TYPE_CUBEMAP:
1285 if (surf->npix_z > 1) {
1288 /* deal with cubemap as they were texture array */
1289 if (surf_man->family >= CHIP_RV770) {
1290 surf->array_size = 8;
1292 surf->array_size = 6;
1295 case RADEON_SURF_TYPE_3D:
1297 case RADEON_SURF_TYPE_1D_ARRAY:
1298 if (surf->npix_y > 1) {
1301 case RADEON_SURF_TYPE_2D_ARRAY:
1309 int radeon_surface_init(struct radeon_surface_manager *surf_man,
1310 struct radeon_surface *surf)
1312 unsigned mode, type;
1315 type = RADEON_SURF_GET(surf->flags, TYPE);
1316 mode = RADEON_SURF_GET(surf->flags, MODE);
1318 r = radeon_surface_sanity(surf_man, surf, type, mode);
1322 return surf_man->surface_init(surf_man, surf);
1325 int radeon_surface_best(struct radeon_surface_manager *surf_man,
1326 struct radeon_surface *surf)
1328 unsigned mode, type;
1331 type = RADEON_SURF_GET(surf->flags, TYPE);
1332 mode = RADEON_SURF_GET(surf->flags, MODE);
1334 r = radeon_surface_sanity(surf_man, surf, type, mode);
1338 return surf_man->surface_best(surf_man, surf);