radeon_bo_helper.c revision de2362d3
1de2362d3Smrg/*
2de2362d3Smrg * Copyright 2012  Advanced Micro Devices, Inc.
3de2362d3Smrg *
4de2362d3Smrg * Permission is hereby granted, free of charge, to any person obtaining a
5de2362d3Smrg * copy of this software and associated documentation files (the "Software"),
6de2362d3Smrg * to deal in the Software without restriction, including without limitation
7de2362d3Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8de2362d3Smrg * and/or sell copies of the Software, and to permit persons to whom the
9de2362d3Smrg * Software is furnished to do so, subject to the following conditions:
10de2362d3Smrg *
11de2362d3Smrg * The above copyright notice and this permission notice shall be included in
12de2362d3Smrg * all copies or substantial portions of the Software.
13de2362d3Smrg *
14de2362d3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15de2362d3Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16de2362d3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17de2362d3Smrg * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18de2362d3Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19de2362d3Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20de2362d3Smrg * OTHER DEALINGS IN THE SOFTWARE.
21de2362d3Smrg */
22de2362d3Smrg
23de2362d3Smrg#ifdef HAVE_CONFIG_H
24de2362d3Smrg# include "config.h"
25de2362d3Smrg#endif
26de2362d3Smrg
27de2362d3Smrg#include "radeon.h"
28de2362d3Smrg
29de2362d3Smrg#ifdef RADEON_PIXMAP_SHARING
30de2362d3Smrg#include "radeon_bo_gem.h"
31de2362d3Smrg#endif
32de2362d3Smrg
33de2362d3Smrgstatic const unsigned MicroBlockTable[5][3][2] = {
34de2362d3Smrg    /*linear  tiled   square-tiled */
35de2362d3Smrg    {{32, 1}, {8, 4}, {0, 0}}, /*   8 bits per pixel */
36de2362d3Smrg    {{16, 1}, {8, 2}, {4, 4}}, /*  16 bits per pixel */
37de2362d3Smrg    {{ 8, 1}, {4, 2}, {0, 0}}, /*  32 bits per pixel */
38de2362d3Smrg    {{ 4, 1}, {0, 0}, {2, 2}}, /*  64 bits per pixel */
39de2362d3Smrg    {{ 2, 1}, {0, 0}, {0, 0}}  /* 128 bits per pixel */
40de2362d3Smrg};
41de2362d3Smrg
42de2362d3Smrg/* Return true if macrotiling can be enabled */
43de2362d3Smrgstatic Bool RADEONMacroSwitch(int width, int height, int bpp,
44de2362d3Smrg                              uint32_t flags, Bool rv350_mode)
45de2362d3Smrg{
46de2362d3Smrg    unsigned tilew, tileh, microtiled, logbpp;
47de2362d3Smrg
48de2362d3Smrg    logbpp = RADEONLog2(bpp / 8);
49de2362d3Smrg    if (logbpp > 4)
50de2362d3Smrg        return 0;
51de2362d3Smrg
52de2362d3Smrg    microtiled = !!(flags & RADEON_TILING_MICRO);
53de2362d3Smrg    tilew = MicroBlockTable[logbpp][microtiled][0] * 8;
54de2362d3Smrg    tileh = MicroBlockTable[logbpp][microtiled][1] * 8;
55de2362d3Smrg
56de2362d3Smrg    /* See TX_FILTER1_n.MACRO_SWITCH. */
57de2362d3Smrg    if (rv350_mode) {
58de2362d3Smrg        return width >= tilew && height >= tileh;
59de2362d3Smrg    } else {
60de2362d3Smrg        return width > tilew && height > tileh;
61de2362d3Smrg    }
62de2362d3Smrg}
63de2362d3Smrg
64de2362d3Smrg/* Calculate appropriate tiling and pitch for a pixmap and allocate a BO that
65de2362d3Smrg * can hold it.
66de2362d3Smrg */
67de2362d3Smrgstruct radeon_bo*
68de2362d3Smrgradeon_alloc_pixmap_bo(ScrnInfoPtr pScrn, int width, int height, int depth,
69de2362d3Smrg		       int usage_hint, int bitsPerPixel, int *new_pitch,
70de2362d3Smrg		       struct radeon_surface *new_surface, uint32_t *new_tiling)
71de2362d3Smrg{
72de2362d3Smrg    RADEONInfoPtr info = RADEONPTR(pScrn);
73de2362d3Smrg    int pitch, base_align;
74de2362d3Smrg    uint32_t size, heighta;
75de2362d3Smrg    int cpp = bitsPerPixel / 8;
76de2362d3Smrg    uint32_t tiling = 0;
77de2362d3Smrg    struct radeon_surface surface;
78de2362d3Smrg    struct radeon_bo *bo;
79de2362d3Smrg    int domain = RADEON_GEM_DOMAIN_VRAM;
80de2362d3Smrg    if (usage_hint) {
81de2362d3Smrg	if (info->allowColorTiling) {
82de2362d3Smrg	    if (usage_hint & RADEON_CREATE_PIXMAP_TILING_MACRO)
83de2362d3Smrg		tiling |= RADEON_TILING_MACRO;
84de2362d3Smrg	    if (usage_hint & RADEON_CREATE_PIXMAP_TILING_MICRO)
85de2362d3Smrg                tiling |= RADEON_TILING_MICRO;
86de2362d3Smrg	}
87de2362d3Smrg	if (usage_hint & RADEON_CREATE_PIXMAP_DEPTH)
88de2362d3Smrg		tiling |= RADEON_TILING_MACRO | RADEON_TILING_MICRO;
89de2362d3Smrg
90de2362d3Smrg#ifdef CREATE_PIXMAP_USAGE_SHARED
91de2362d3Smrg	if ((usage_hint & 0xffff) == CREATE_PIXMAP_USAGE_SHARED) {
92de2362d3Smrg		tiling = 0;
93de2362d3Smrg		domain = RADEON_GEM_DOMAIN_GTT;
94de2362d3Smrg	}
95de2362d3Smrg#endif
96de2362d3Smrg    }
97de2362d3Smrg
98de2362d3Smrg    /* Small pixmaps must not be macrotiled on R300, hw cannot sample them
99de2362d3Smrg     * correctly because samplers automatically switch to macrolinear. */
100de2362d3Smrg    if (info->ChipFamily >= CHIP_FAMILY_R300 &&
101de2362d3Smrg        info->ChipFamily <= CHIP_FAMILY_RS740 &&
102de2362d3Smrg        (tiling & RADEON_TILING_MACRO) &&
103de2362d3Smrg        !RADEONMacroSwitch(width, height, bitsPerPixel, tiling,
104de2362d3Smrg                           info->ChipFamily >= CHIP_FAMILY_RV350)) {
105de2362d3Smrg        tiling &= ~RADEON_TILING_MACRO;
106de2362d3Smrg    }
107de2362d3Smrg
108de2362d3Smrg    heighta = RADEON_ALIGN(height, drmmode_get_height_align(pScrn, tiling));
109de2362d3Smrg    pitch = RADEON_ALIGN(width, drmmode_get_pitch_align(pScrn, cpp, tiling)) * cpp;
110de2362d3Smrg    base_align = drmmode_get_base_align(pScrn, cpp, tiling);
111de2362d3Smrg    size = RADEON_ALIGN(heighta * pitch, RADEON_GPU_PAGE_SIZE);
112de2362d3Smrg    memset(&surface, 0, sizeof(struct radeon_surface));
113de2362d3Smrg
114de2362d3Smrg    if (info->ChipFamily >= CHIP_FAMILY_R600 && info->surf_man) {
115de2362d3Smrg		if (width) {
116de2362d3Smrg			surface.npix_x = width;
117de2362d3Smrg			/* need to align height to 8 for old kernel */
118de2362d3Smrg			surface.npix_y = RADEON_ALIGN(height, 8);
119de2362d3Smrg			surface.npix_z = 1;
120de2362d3Smrg			surface.blk_w = 1;
121de2362d3Smrg			surface.blk_h = 1;
122de2362d3Smrg			surface.blk_d = 1;
123de2362d3Smrg			surface.array_size = 1;
124de2362d3Smrg			surface.last_level = 0;
125de2362d3Smrg			surface.bpe = cpp;
126de2362d3Smrg			surface.nsamples = 1;
127de2362d3Smrg			if (height < 128) {
128de2362d3Smrg				/* disable 2d tiling for small surface to work around
129de2362d3Smrg				 * the fact that ddx align height to 8 pixel for old
130de2362d3Smrg				 * obscure reason i can't remember
131de2362d3Smrg				 */
132de2362d3Smrg				tiling &= ~RADEON_TILING_MACRO;
133de2362d3Smrg			}
134de2362d3Smrg			surface.flags = RADEON_SURF_SCANOUT;
135de2362d3Smrg			/* we are requiring a recent enough libdrm version */
136de2362d3Smrg			surface.flags |= RADEON_SURF_HAS_TILE_MODE_INDEX;
137de2362d3Smrg			surface.flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_2D, TYPE);
138de2362d3Smrg			surface.flags |= RADEON_SURF_SET(RADEON_SURF_MODE_LINEAR, MODE);
139de2362d3Smrg			if ((tiling & RADEON_TILING_MICRO)) {
140de2362d3Smrg				surface.flags = RADEON_SURF_CLR(surface.flags, MODE);
141de2362d3Smrg				surface.flags |= RADEON_SURF_SET(RADEON_SURF_MODE_1D, MODE);
142de2362d3Smrg			}
143de2362d3Smrg			if ((tiling & RADEON_TILING_MACRO)) {
144de2362d3Smrg				surface.flags = RADEON_SURF_CLR(surface.flags, MODE);
145de2362d3Smrg				surface.flags |= RADEON_SURF_SET(RADEON_SURF_MODE_2D, MODE);
146de2362d3Smrg			}
147de2362d3Smrg			if (usage_hint & RADEON_CREATE_PIXMAP_SZBUFFER) {
148de2362d3Smrg				surface.flags |= RADEON_SURF_ZBUFFER;
149de2362d3Smrg				surface.flags |= RADEON_SURF_SBUFFER;
150de2362d3Smrg			}
151de2362d3Smrg			if (radeon_surface_best(info->surf_man, &surface)) {
152de2362d3Smrg				return NULL;
153de2362d3Smrg			}
154de2362d3Smrg			if (radeon_surface_init(info->surf_man, &surface)) {
155de2362d3Smrg				return NULL;
156de2362d3Smrg			}
157de2362d3Smrg			size = surface.bo_size;
158de2362d3Smrg			base_align = surface.bo_alignment;
159de2362d3Smrg			pitch = surface.level[0].pitch_bytes;
160de2362d3Smrg			tiling = 0;
161de2362d3Smrg			switch (surface.level[0].mode) {
162de2362d3Smrg			case RADEON_SURF_MODE_2D:
163de2362d3Smrg				tiling |= RADEON_TILING_MACRO;
164de2362d3Smrg				tiling |= surface.bankw << RADEON_TILING_EG_BANKW_SHIFT;
165de2362d3Smrg				tiling |= surface.bankh << RADEON_TILING_EG_BANKH_SHIFT;
166de2362d3Smrg				tiling |= surface.mtilea << RADEON_TILING_EG_MACRO_TILE_ASPECT_SHIFT;
167de2362d3Smrg				tiling |= eg_tile_split(surface.tile_split) << RADEON_TILING_EG_TILE_SPLIT_SHIFT;
168de2362d3Smrg				tiling |= eg_tile_split(surface.stencil_tile_split) << RADEON_TILING_EG_STENCIL_TILE_SPLIT_SHIFT;
169de2362d3Smrg				break;
170de2362d3Smrg			case RADEON_SURF_MODE_1D:
171de2362d3Smrg				tiling |= RADEON_TILING_MICRO;
172de2362d3Smrg				break;
173de2362d3Smrg			default:
174de2362d3Smrg				break;
175de2362d3Smrg			}
176de2362d3Smrg		}
177de2362d3Smrg	}
178de2362d3Smrg
179de2362d3Smrg    bo = radeon_bo_open(info->bufmgr, 0, size, base_align,
180de2362d3Smrg			domain, 0);
181de2362d3Smrg
182de2362d3Smrg    if (bo && tiling && radeon_bo_set_tiling(bo, tiling, pitch) == 0)
183de2362d3Smrg	*new_tiling = tiling;
184de2362d3Smrg
185de2362d3Smrg    *new_surface = surface;
186de2362d3Smrg    *new_pitch = pitch;
187de2362d3Smrg    return bo;
188de2362d3Smrg}
189de2362d3Smrg
190de2362d3Smrg#ifdef RADEON_PIXMAP_SHARING
191de2362d3Smrg
192de2362d3SmrgBool radeon_share_pixmap_backing(struct radeon_bo *bo, void **handle_p)
193de2362d3Smrg{
194de2362d3Smrg    int handle;
195de2362d3Smrg
196de2362d3Smrg    if (radeon_gem_prime_share_bo(bo, &handle) != 0)
197de2362d3Smrg	return FALSE;
198de2362d3Smrg
199de2362d3Smrg    *handle_p = (void *)(long)handle;
200de2362d3Smrg    return TRUE;
201de2362d3Smrg}
202de2362d3Smrg
203de2362d3SmrgBool radeon_set_shared_pixmap_backing(PixmapPtr ppix, void *fd_handle,
204de2362d3Smrg				      struct radeon_surface *surface)
205de2362d3Smrg{
206de2362d3Smrg    ScrnInfoPtr pScrn = xf86ScreenToScrn(ppix->drawable.pScreen);
207de2362d3Smrg    RADEONInfoPtr info = RADEONPTR(pScrn);
208de2362d3Smrg    struct radeon_bo *bo;
209de2362d3Smrg    int ihandle = (int)(long)fd_handle;
210de2362d3Smrg    uint32_t size = ppix->devKind * ppix->drawable.height;
211de2362d3Smrg
212de2362d3Smrg    bo = radeon_gem_bo_open_prime(info->bufmgr, ihandle, size);
213de2362d3Smrg    if (!bo)
214de2362d3Smrg        return FALSE;
215de2362d3Smrg
216de2362d3Smrg    memset(surface, 0, sizeof(struct radeon_surface));
217de2362d3Smrg
218de2362d3Smrg    if (info->ChipFamily >= CHIP_FAMILY_R600 && info->surf_man) {
219de2362d3Smrg
220de2362d3Smrg	surface->npix_x = ppix->drawable.width;
221de2362d3Smrg	surface->npix_y = ppix->drawable.height;
222de2362d3Smrg	surface->npix_z = 1;
223de2362d3Smrg	surface->blk_w = 1;
224de2362d3Smrg	surface->blk_h = 1;
225de2362d3Smrg	surface->blk_d = 1;
226de2362d3Smrg	surface->array_size = 1;
227de2362d3Smrg	surface->bpe = ppix->drawable.bitsPerPixel / 8;
228de2362d3Smrg	surface->nsamples = 1;
229de2362d3Smrg	/* we are requiring a recent enough libdrm version */
230de2362d3Smrg	surface->flags |= RADEON_SURF_HAS_TILE_MODE_INDEX;
231de2362d3Smrg	surface->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_2D, TYPE);
232de2362d3Smrg	surface->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_LINEAR, MODE);
233de2362d3Smrg	if (radeon_surface_best(info->surf_man, surface)) {
234de2362d3Smrg	    return FALSE;
235de2362d3Smrg	}
236de2362d3Smrg	if (radeon_surface_init(info->surf_man, surface)) {
237de2362d3Smrg	    return FALSE;
238de2362d3Smrg	}
239de2362d3Smrg	/* we have to post hack the surface to reflect the actual size
240de2362d3Smrg	   of the shared pixmap */
241de2362d3Smrg	surface->level[0].pitch_bytes = ppix->devKind;
242de2362d3Smrg	surface->level[0].nblk_x = ppix->devKind / surface->bpe;
243de2362d3Smrg    }
244de2362d3Smrg    radeon_set_pixmap_bo(ppix, bo);
245de2362d3Smrg
246de2362d3Smrg    close(ihandle);
247de2362d3Smrg    /* we have a reference from the alloc and one from set pixmap bo,
248de2362d3Smrg       drop one */
249de2362d3Smrg    radeon_bo_unref(bo);
250de2362d3Smrg    return TRUE;
251de2362d3Smrg}
252de2362d3Smrg
253de2362d3Smrg#endif /* RADEON_PIXMAP_SHARING */
254