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,
148 uint32_t xalign, uint32_t yalign, uint32_t zalign,
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->nsamples == 1 && 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;
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 * surf->nsamples;
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;
174 /* ===========================================================================
177 static int r6_init_hw_info(struct radeon_surface_manager *surf_man)
179 uint32_t tiling_config;
180 drmVersionPtr version;
183 r = radeon_get_value(surf_man->fd, RADEON_INFO_TILING_CONFIG,
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;
194 drmFreeVersion(version);
196 switch ((tiling_config & 0xe) >> 1) {
198 surf_man->hw_info.num_pipes = 1;
201 surf_man->hw_info.num_pipes = 2;
204 surf_man->hw_info.num_pipes = 4;
207 surf_man->hw_info.num_pipes = 8;
210 surf_man->hw_info.num_pipes = 8;
211 surf_man->hw_info.allow_2d = 0;
215 switch ((tiling_config & 0x30) >> 4) {
217 surf_man->hw_info.num_banks = 4;
220 surf_man->hw_info.num_banks = 8;
223 surf_man->hw_info.num_banks = 8;
224 surf_man->hw_info.allow_2d = 0;
228 switch ((tiling_config & 0xc0) >> 6) {
230 surf_man->hw_info.group_bytes = 256;
233 surf_man->hw_info.group_bytes = 512;
236 surf_man->hw_info.group_bytes = 256;
237 surf_man->hw_info.allow_2d = 0;
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)
247 uint32_t xalign, yalign, zalign;
250 /* compute alignment */
252 surf->bo_alignment = MAX2(256, surf_man->hw_info.group_bytes);
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
257 xalign = MAX2(1, surf_man->hw_info.group_bytes / surf->bpe);
260 if (surf->flags & RADEON_SURF_SCANOUT) {
261 xalign = MAX2((surf->bpe == 1) ? 64 : 32, xalign);
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;
271 offset = ALIGN(offset, surf->bo_alignment);
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)
281 uint32_t xalign, yalign, zalign;
284 /* compute alignment */
286 surf->bo_alignment = MAX2(256, surf_man->hw_info.group_bytes);
288 xalign = MAX2(64, surf_man->hw_info.group_bytes / surf->bpe);
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;
299 offset = ALIGN(offset, surf->bo_alignment);
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)
309 uint32_t xalign, yalign, zalign, tilew;
312 /* compute alignment */
314 xalign = surf_man->hw_info.group_bytes / (tilew * surf->bpe * surf->nsamples);
315 xalign = MAX2(tilew, xalign);
318 if (surf->flags & RADEON_SURF_SCANOUT) {
319 xalign = MAX2((surf->bpe == 1) ? 64 : 32, xalign);
322 surf->bo_alignment = MAX2(256, surf_man->hw_info.group_bytes);
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;
332 offset = ALIGN(offset, surf->bo_alignment);
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)
342 uint32_t xalign, yalign, zalign, tilew;
345 /* compute alignment */
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);
357 MAX2(surf_man->hw_info.num_pipes *
358 surf_man->hw_info.num_banks *
359 surf->nsamples * surf->bpe * 64,
360 xalign * yalign * surf->nsamples * surf->bpe);
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);
370 /* level0 and first mipmap need to have alignment */
371 offset = surf->bo_size;
373 offset = ALIGN(offset, surf->bo_alignment);
379 static int r6_surface_init(struct radeon_surface_manager *surf_man,
380 struct radeon_surface *surf)
385 /* MSAA surfaces support the 2D mode only. */
386 if (surf->nsamples > 1) {
387 surf->flags = RADEON_SURF_CLR(surf->flags, MODE);
388 surf->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_2D, MODE);
392 mode = (surf->flags >> RADEON_SURF_MODE_SHIFT) & RADEON_SURF_MODE_MASK;
394 if (surf->flags & (RADEON_SURF_ZBUFFER | RADEON_SURF_SBUFFER)) {
395 /* zbuffer only support 1D or 2D tiled surface */
397 case RADEON_SURF_MODE_1D:
398 case RADEON_SURF_MODE_2D:
401 mode = RADEON_SURF_MODE_1D;
402 surf->flags = RADEON_SURF_CLR(surf->flags, MODE);
403 surf->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_1D, MODE);
408 /* force 1d on kernel that can't do 2d */
409 if (!surf_man->hw_info.allow_2d && mode > RADEON_SURF_MODE_1D) {
410 if (surf->nsamples > 1) {
411 fprintf(stderr, "radeon: Cannot use 2D tiling for an MSAA surface (%i).\n", __LINE__);
414 mode = RADEON_SURF_MODE_1D;
415 surf->flags = RADEON_SURF_CLR(surf->flags, MODE);
416 surf->flags |= RADEON_SURF_SET(mode, MODE);
419 /* check surface dimension */
420 if (surf->npix_x > 8192 || surf->npix_y > 8192 || surf->npix_z > 8192) {
424 /* check mipmap last_level */
425 if (surf->last_level > 14) {
429 /* check tiling mode */
431 case RADEON_SURF_MODE_LINEAR:
432 r = r6_surface_init_linear(surf_man, surf, 0, 0);
434 case RADEON_SURF_MODE_LINEAR_ALIGNED:
435 r = r6_surface_init_linear_aligned(surf_man, surf, 0, 0);
437 case RADEON_SURF_MODE_1D:
438 r = r6_surface_init_1d(surf_man, surf, 0, 0);
440 case RADEON_SURF_MODE_2D:
441 r = r6_surface_init_2d(surf_man, surf, 0, 0);
449 static int r6_surface_best(struct radeon_surface_manager *surf_man,
450 struct radeon_surface *surf)
452 /* no value to optimize for r6xx/r7xx */
457 /* ===========================================================================
460 static int eg_init_hw_info(struct radeon_surface_manager *surf_man)
462 uint32_t tiling_config;
463 drmVersionPtr version;
466 r = radeon_get_value(surf_man->fd, RADEON_INFO_TILING_CONFIG,
472 surf_man->hw_info.allow_2d = 0;
473 version = drmGetVersion(surf_man->fd);
474 if (version && version->version_minor >= 16) {
475 surf_man->hw_info.allow_2d = 1;
477 drmFreeVersion(version);
479 switch (tiling_config & 0xf) {
481 surf_man->hw_info.num_pipes = 1;
484 surf_man->hw_info.num_pipes = 2;
487 surf_man->hw_info.num_pipes = 4;
490 surf_man->hw_info.num_pipes = 8;
493 surf_man->hw_info.num_pipes = 8;
494 surf_man->hw_info.allow_2d = 0;
498 switch ((tiling_config & 0xf0) >> 4) {
500 surf_man->hw_info.num_banks = 4;
503 surf_man->hw_info.num_banks = 8;
506 surf_man->hw_info.num_banks = 16;
509 surf_man->hw_info.num_banks = 8;
510 surf_man->hw_info.allow_2d = 0;
514 switch ((tiling_config & 0xf00) >> 8) {
516 surf_man->hw_info.group_bytes = 256;
519 surf_man->hw_info.group_bytes = 512;
522 surf_man->hw_info.group_bytes = 256;
523 surf_man->hw_info.allow_2d = 0;
527 switch ((tiling_config & 0xf000) >> 12) {
529 surf_man->hw_info.row_size = 1024;
532 surf_man->hw_info.row_size = 2048;
535 surf_man->hw_info.row_size = 4096;
538 surf_man->hw_info.row_size = 4096;
539 surf_man->hw_info.allow_2d = 0;
545 static void eg_surf_minify(struct radeon_surface *surf,
553 unsigned mtile_pr, mtile_ps;
555 surf->level[level].npix_x = mip_minify(surf->npix_x, level);
556 surf->level[level].npix_y = mip_minify(surf->npix_y, level);
557 surf->level[level].npix_z = mip_minify(surf->npix_z, level);
558 surf->level[level].nblk_x = (surf->level[level].npix_x + surf->blk_w - 1) / surf->blk_w;
559 surf->level[level].nblk_y = (surf->level[level].npix_y + surf->blk_h - 1) / surf->blk_h;
560 surf->level[level].nblk_z = (surf->level[level].npix_z + surf->blk_d - 1) / surf->blk_d;
561 if (surf->nsamples == 1 && surf->level[level].mode == RADEON_SURF_MODE_2D) {
562 if (surf->level[level].nblk_x < mtilew || surf->level[level].nblk_y < mtileh) {
563 surf->level[level].mode = RADEON_SURF_MODE_1D;
567 surf->level[level].nblk_x = ALIGN(surf->level[level].nblk_x, mtilew);
568 surf->level[level].nblk_y = ALIGN(surf->level[level].nblk_y, mtileh);
569 surf->level[level].nblk_z = ALIGN(surf->level[level].nblk_z, 1);
571 /* macro tile per row */
572 mtile_pr = surf->level[level].nblk_x / mtilew;
573 /* macro tile per slice */
574 mtile_ps = (mtile_pr * surf->level[level].nblk_y) / mtileh;
576 surf->level[level].offset = offset;
577 surf->level[level].pitch_bytes = surf->level[level].nblk_x * surf->bpe * slice_pt;
578 surf->level[level].slice_size = mtile_ps * mtileb * slice_pt;
580 surf->bo_size = offset + surf->level[level].slice_size * surf->level[level].nblk_z * surf->array_size;
583 static int eg_surface_init_1d(struct radeon_surface_manager *surf_man,
584 struct radeon_surface *surf,
585 uint64_t offset, unsigned start_level)
587 uint32_t xalign, yalign, zalign, tilew;
590 /* compute alignment */
592 xalign = surf_man->hw_info.group_bytes / (tilew * surf->bpe * surf->nsamples);
593 if (surf->flags & RADEON_SURF_SBUFFER) {
594 xalign = surf_man->hw_info.group_bytes / (tilew * surf->nsamples);
596 xalign = MAX2(tilew, xalign);
599 if (surf->flags & RADEON_SURF_SCANOUT) {
600 xalign = MAX2((surf->bpe == 1) ? 64 : 32, xalign);
603 surf->bo_alignment = MAX2(256, surf_man->hw_info.group_bytes);
606 /* build mipmap tree */
607 for (i = start_level; i <= surf->last_level; i++) {
608 surf->level[i].mode = RADEON_SURF_MODE_1D;
609 surf_minify(surf, i, xalign, yalign, zalign, offset);
610 /* level0 and first mipmap need to have alignment */
611 offset = surf->bo_size;
613 offset = ALIGN(offset, surf->bo_alignment);
617 /* The depth and stencil buffers are in separate resources on evergreen.
618 * We allocate them in one buffer next to each other to simplify
619 * communication between the DDX and the Mesa driver. */
620 if ((surf->flags & (RADEON_SURF_ZBUFFER | RADEON_SURF_SBUFFER)) ==
621 (RADEON_SURF_ZBUFFER | RADEON_SURF_SBUFFER)) {
622 surf->stencil_offset = ALIGN(surf->bo_size, surf->bo_alignment);
623 surf->bo_size = surf->stencil_offset + surf->bo_size / 4;
629 static int eg_surface_init_2d(struct radeon_surface_manager *surf_man,
630 struct radeon_surface *surf,
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 * surf->bpe * surf->nsamples;
642 /* slices per tile */
644 if (tileb > surf->tile_split) {
645 slice_pt = tileb / surf->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 surf->bo_alignment = MAX2(256, mtileb);
659 /* build mipmap tree */
660 for (i = start_level; i <= surf->last_level; i++) {
661 surf->level[i].mode = RADEON_SURF_MODE_2D;
662 eg_surf_minify(surf, i, slice_pt, mtilew, mtileh, mtileb, offset);
663 if (surf->level[i].mode == RADEON_SURF_MODE_1D) {
664 return eg_surface_init_1d(surf_man, surf, offset, i);
666 /* level0 and first mipmap need to have alignment */
667 offset = surf->bo_size;
669 offset = ALIGN(offset, surf->bo_alignment);
673 if ((surf->flags & (RADEON_SURF_ZBUFFER | RADEON_SURF_SBUFFER)) ==
674 (RADEON_SURF_ZBUFFER | RADEON_SURF_SBUFFER)) {
675 surf->stencil_offset = ALIGN(surf->bo_size, surf->bo_alignment);
676 surf->bo_size = surf->stencil_offset + surf->bo_size / 4;
682 static int eg_surface_sanity(struct radeon_surface_manager *surf_man,
683 struct radeon_surface *surf,
688 /* check surface dimension */
689 if (surf->npix_x > 16384 || surf->npix_y > 16384 || surf->npix_z > 16384) {
693 /* check mipmap last_level */
694 if (surf->last_level > 15) {
698 /* force 1d on kernel that can't do 2d */
699 if (!surf_man->hw_info.allow_2d && mode > RADEON_SURF_MODE_1D) {
700 if (surf->nsamples > 1) {
701 fprintf(stderr, "radeon: Cannot use 2D tiling for an MSAA surface (%i).\n", __LINE__);
704 mode = RADEON_SURF_MODE_1D;
705 surf->flags = RADEON_SURF_CLR(surf->flags, MODE);
706 surf->flags |= RADEON_SURF_SET(mode, MODE);
709 /* check tile split */
710 if (mode == RADEON_SURF_MODE_2D) {
711 switch (surf->tile_split) {
723 switch (surf->mtilea) {
732 /* check aspect ratio */
733 if (surf_man->hw_info.num_banks < surf->mtilea) {
736 /* check bank width */
737 switch (surf->bankw) {
746 /* check bank height */
747 switch (surf->bankh) {
756 tileb = MIN2(surf->tile_split, 64 * surf->bpe * surf->nsamples);
757 if ((tileb * surf->bankh * surf->bankw) < surf_man->hw_info.group_bytes) {
765 static int eg_surface_init(struct radeon_surface_manager *surf_man,
766 struct radeon_surface *surf)
771 /* MSAA surfaces support the 2D mode only. */
772 if (surf->nsamples > 1) {
773 surf->flags = RADEON_SURF_CLR(surf->flags, MODE);
774 surf->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_2D, MODE);
778 mode = (surf->flags >> RADEON_SURF_MODE_SHIFT) & RADEON_SURF_MODE_MASK;
780 if (surf->flags & (RADEON_SURF_ZBUFFER | RADEON_SURF_SBUFFER)) {
781 /* zbuffer only support 1D or 2D tiled surface */
783 case RADEON_SURF_MODE_1D:
784 case RADEON_SURF_MODE_2D:
787 mode = RADEON_SURF_MODE_1D;
788 surf->flags = RADEON_SURF_CLR(surf->flags, MODE);
789 surf->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_1D, MODE);
794 r = eg_surface_sanity(surf_man, surf, mode);
799 surf->stencil_offset = 0;
801 /* check tiling mode */
803 case RADEON_SURF_MODE_LINEAR:
804 r = r6_surface_init_linear(surf_man, surf, 0, 0);
806 case RADEON_SURF_MODE_LINEAR_ALIGNED:
807 r = r6_surface_init_linear_aligned(surf_man, surf, 0, 0);
809 case RADEON_SURF_MODE_1D:
810 r = eg_surface_init_1d(surf_man, surf, 0, 0);
812 case RADEON_SURF_MODE_2D:
813 r = eg_surface_init_2d(surf_man, surf, 0, 0);
821 static unsigned log2_int(unsigned x)
829 if ((unsigned)(1 << l) > x) {
836 /* compute best tile_split, bankw, bankh, mtilea
837 * depending on surface
839 static int eg_surface_best(struct radeon_surface_manager *surf_man,
840 struct radeon_surface *surf)
842 unsigned mode, tileb, h_over_w;
846 mode = (surf->flags >> RADEON_SURF_MODE_SHIFT) & RADEON_SURF_MODE_MASK;
848 /* set some default value to avoid sanity check choking on them */
849 surf->tile_split = 1024;
852 surf->mtilea = surf_man->hw_info.num_banks;
853 tileb = MIN2(surf->tile_split, 64 * surf->bpe * surf->nsamples);
854 for (; surf->bankh <= 8; surf->bankh *= 2) {
855 if ((tileb * surf->bankh * surf->bankw) >= surf_man->hw_info.group_bytes) {
859 if (surf->mtilea > 8) {
863 r = eg_surface_sanity(surf_man, surf, mode);
868 if (mode != RADEON_SURF_MODE_2D) {
869 /* nothing to do for non 2D tiled surface */
873 /* Tweak TILE_SPLIT for performance here. */
874 if (surf->nsamples > 1) {
875 if (surf->flags & (RADEON_SURF_ZBUFFER | RADEON_SURF_SBUFFER)) {
876 switch (surf->nsamples) {
878 surf->tile_split = 128;
881 surf->tile_split = 128;
884 surf->tile_split = 256;
886 case 16: /* cayman only */
887 surf->tile_split = 512;
890 fprintf(stderr, "radeon: Wrong number of samples %i (%i)\n",
891 surf->nsamples, __LINE__);
894 surf->stencil_tile_split = 64;
896 /* tile split must be >= 256 for colorbuffer surfaces */
897 surf->tile_split = MAX2(surf->nsamples * surf->bpe * 64, 256);
900 /* set tile split to row size */
901 surf->tile_split = surf_man->hw_info.row_size;
902 surf->stencil_tile_split = surf_man->hw_info.row_size / 2;
905 /* bankw or bankh greater than 1 increase alignment requirement, not
906 * sure if it's worth using smaller bankw & bankh to stick with 2D
907 * tiling on small surface rather than falling back to 1D tiling.
908 * Use recommanded value based on tile size for now.
910 * fmask buffer has different optimal value figure them out once we
913 if (surf->flags & RADEON_SURF_SBUFFER) {
914 /* assume 1 bytes for stencil, we optimize for stencil as stencil
915 * and depth shares surface values
917 tileb = MIN2(surf->tile_split, 64 * surf->nsamples);
919 tileb = MIN2(surf->tile_split, 64 * surf->bpe * surf->nsamples);
922 /* use bankw of 1 to minimize width alignment, might be interesting to
923 * increase it for large surface
938 /* double check the constraint */
939 for (; surf->bankh <= 8; surf->bankh *= 2) {
940 if ((tileb * surf->bankh * surf->bankw) >= surf_man->hw_info.group_bytes) {
945 h_over_w = (((surf->bankh * surf_man->hw_info.num_banks) << 16) /
946 (surf->bankw * surf_man->hw_info.num_pipes)) >> 16;
947 surf->mtilea = 1 << (log2_int(h_over_w) >> 1);
953 /* ===========================================================================
954 * Southern Islands family
957 static void si_surf_minify_linear_aligned(struct radeon_surface *surf,
959 uint32_t xalign, uint32_t yalign, uint32_t zalign, uint32_t slice_align,
962 surf->level[level].npix_x = mip_minify(surf->npix_x, level);
963 surf->level[level].npix_y = mip_minify(surf->npix_y, level);
964 surf->level[level].npix_z = mip_minify(surf->npix_z, level);
966 if (level == 0 && surf->last_level > 0) {
967 surf->level[level].nblk_x = (next_power_of_two(surf->level[level].npix_x) + surf->blk_w - 1) / surf->blk_w;
968 surf->level[level].nblk_y = (next_power_of_two(surf->level[level].npix_y) + surf->blk_h - 1) / surf->blk_h;
969 surf->level[level].nblk_z = (next_power_of_two(surf->level[level].npix_z) + surf->blk_d - 1) / surf->blk_d;
971 surf->level[level].nblk_x = (surf->level[level].npix_x + surf->blk_w - 1) / surf->blk_w;
972 surf->level[level].nblk_y = (surf->level[level].npix_y + surf->blk_h - 1) / surf->blk_h;
973 surf->level[level].nblk_z = (surf->level[level].npix_z + surf->blk_d - 1) / surf->blk_d;
976 /* XXX: Texture sampling uses unexpectedly large pitches in some cases,
977 * these are just guesses for the rules behind those
979 if (level == 0 && surf->last_level == 0)
980 /* Non-mipmap pitch padded to slice alignment */
981 xalign = MAX2(xalign, slice_align / surf->bpe);
983 /* Small rows evenly distributed across slice */
984 xalign = MAX2(xalign, slice_align / surf->bpe / surf->level[level].npix_y);
986 surf->level[level].nblk_x = ALIGN(surf->level[level].nblk_x, xalign);
987 surf->level[level].nblk_y = ALIGN(surf->level[level].nblk_y, yalign);
988 surf->level[level].nblk_z = ALIGN(surf->level[level].nblk_z, zalign);
990 surf->level[level].offset = offset;
991 surf->level[level].pitch_bytes = surf->level[level].nblk_x * surf->bpe * surf->nsamples;
992 surf->level[level].slice_size = ALIGN(surf->level[level].pitch_bytes * surf->level[level].nblk_y, slice_align);
994 surf->bo_size = offset + surf->level[level].slice_size * surf->level[level].nblk_z * surf->array_size;
997 static int si_surface_init_linear_aligned(struct radeon_surface_manager *surf_man,
998 struct radeon_surface *surf,
999 uint64_t offset, unsigned start_level)
1001 uint32_t xalign, yalign, zalign, slice_align;
1004 /* compute alignment */
1006 surf->bo_alignment = MAX2(256, surf_man->hw_info.group_bytes);
1008 xalign = MAX2(8, 64 / surf->bpe);
1011 slice_align = MAX2(64 * surf->bpe, surf_man->hw_info.group_bytes);
1013 /* build mipmap tree */
1014 for (i = start_level; i <= surf->last_level; i++) {
1015 surf->level[i].mode = RADEON_SURF_MODE_LINEAR_ALIGNED;
1016 si_surf_minify_linear_aligned(surf, i, xalign, yalign, zalign, slice_align, offset);
1017 /* level0 and first mipmap need to have alignment */
1018 offset = surf->bo_size;
1020 offset = ALIGN(offset, surf->bo_alignment);
1026 static int si_surface_init(struct radeon_surface_manager *surf_man,
1027 struct radeon_surface *surf)
1032 /* MSAA surfaces support the 2D mode only. */
1033 if (surf->nsamples > 1) {
1034 surf->flags = RADEON_SURF_CLR(surf->flags, MODE);
1035 surf->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_2D, MODE);
1039 mode = (surf->flags >> RADEON_SURF_MODE_SHIFT) & RADEON_SURF_MODE_MASK;
1041 if (surf->flags & (RADEON_SURF_ZBUFFER | RADEON_SURF_SBUFFER)) {
1042 /* zbuffer only support 1D or 2D tiled surface */
1044 case RADEON_SURF_MODE_1D:
1045 case RADEON_SURF_MODE_2D:
1048 mode = RADEON_SURF_MODE_1D;
1049 surf->flags = RADEON_SURF_CLR(surf->flags, MODE);
1050 surf->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_1D, MODE);
1055 r = eg_surface_sanity(surf_man, surf, mode);
1060 surf->stencil_offset = 0;
1062 /* check tiling mode */
1064 case RADEON_SURF_MODE_LINEAR:
1065 r = r6_surface_init_linear(surf_man, surf, 0, 0);
1067 case RADEON_SURF_MODE_LINEAR_ALIGNED:
1068 r = si_surface_init_linear_aligned(surf_man, surf, 0, 0);
1070 case RADEON_SURF_MODE_1D:
1071 r = eg_surface_init_1d(surf_man, surf, 0, 0);
1073 case RADEON_SURF_MODE_2D:
1074 r = eg_surface_init_2d(surf_man, surf, 0, 0);
1082 /* ===========================================================================
1085 struct radeon_surface_manager *radeon_surface_manager_new(int fd)
1087 struct radeon_surface_manager *surf_man;
1089 surf_man = calloc(1, sizeof(struct radeon_surface_manager));
1090 if (surf_man == NULL) {
1094 if (radeon_get_value(fd, RADEON_INFO_DEVICE_ID, &surf_man->device_id)) {
1097 if (radeon_get_family(surf_man)) {
1101 if (surf_man->family <= CHIP_RV740) {
1102 if (r6_init_hw_info(surf_man)) {
1105 surf_man->surface_init = &r6_surface_init;
1106 surf_man->surface_best = &r6_surface_best;
1108 if (eg_init_hw_info(surf_man)) {
1111 if (surf_man->family <= CHIP_ARUBA) {
1112 surf_man->surface_init = &eg_surface_init;
1114 surf_man->surface_init = &si_surface_init;
1116 surf_man->surface_best = &eg_surface_best;
1125 void radeon_surface_manager_free(struct radeon_surface_manager *surf_man)
1130 static int radeon_surface_sanity(struct radeon_surface_manager *surf_man,
1131 struct radeon_surface *surf,
1135 if (surf_man == NULL || surf_man->surface_init == NULL || surf == NULL) {
1139 /* all dimension must be at least 1 ! */
1140 if (!surf->npix_x || !surf->npix_y || !surf->npix_z) {
1143 if (!surf->blk_w || !surf->blk_h || !surf->blk_d) {
1146 if (!surf->array_size) {
1149 /* array size must be a power of 2 */
1150 surf->array_size = next_power_of_two(surf->array_size);
1152 switch (surf->nsamples) {
1163 case RADEON_SURF_TYPE_1D:
1164 if (surf->npix_y > 1) {
1167 case RADEON_SURF_TYPE_2D:
1168 if (surf->npix_z > 1) {
1172 case RADEON_SURF_TYPE_CUBEMAP:
1173 if (surf->npix_z > 1) {
1176 /* deal with cubemap as they were texture array */
1177 if (surf_man->family >= CHIP_RV770) {
1178 surf->array_size = 8;
1180 surf->array_size = 6;
1183 case RADEON_SURF_TYPE_3D:
1185 case RADEON_SURF_TYPE_1D_ARRAY:
1186 if (surf->npix_y > 1) {
1189 case RADEON_SURF_TYPE_2D_ARRAY:
1197 int radeon_surface_init(struct radeon_surface_manager *surf_man,
1198 struct radeon_surface *surf)
1200 unsigned mode, type;
1203 type = RADEON_SURF_GET(surf->flags, TYPE);
1204 mode = RADEON_SURF_GET(surf->flags, MODE);
1206 r = radeon_surface_sanity(surf_man, surf, type, mode);
1210 return surf_man->surface_init(surf_man, surf);
1213 int radeon_surface_best(struct radeon_surface_manager *surf_man,
1214 struct radeon_surface *surf)
1216 unsigned mode, type;
1219 type = RADEON_SURF_GET(surf->flags, TYPE);
1220 mode = RADEON_SURF_GET(surf->flags, MODE);
1222 r = radeon_surface_sanity(surf_man, surf, type, mode);
1226 return surf_man->surface_best(surf_man, surf);