1fda9279dSmrg/*
2fda9279dSmrg * Copyright 2009 Nouveau Project
3fda9279dSmrg *
4fda9279dSmrg * Permission is hereby granted, free of charge, to any person obtaining a
5fda9279dSmrg * copy of this software and associated documentation files (the "Software"),
6fda9279dSmrg * to deal in the Software without restriction, including without limitation
7fda9279dSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8fda9279dSmrg * and/or sell copies of the Software, and to permit persons to whom the
9fda9279dSmrg * Software is furnished to do so, subject to the following conditions:
10fda9279dSmrg *
11fda9279dSmrg * The above copyright notice and this permission notice shall be included in
12fda9279dSmrg * all copies or substantial portions of the Software.
13fda9279dSmrg *
14fda9279dSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15fda9279dSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16fda9279dSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17fda9279dSmrg * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18fda9279dSmrg * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
19fda9279dSmrg * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20fda9279dSmrg * SOFTWARE.
21fda9279dSmrg */
22fda9279dSmrg
23fda9279dSmrg#include "nv_include.h"
24fda9279dSmrg#include "exa.h"
25fda9279dSmrg
26fda9279dSmrg#include "hwdefs/nv_m2mf.xml.h"
27fda9279dSmrg
28fda9279dSmrgstatic inline Bool
29fda9279dSmrgNVAccelMemcpyRect(char *dst, const char *src, int height, int dst_pitch,
30fda9279dSmrg		  int src_pitch, int line_len)
31fda9279dSmrg{
32fda9279dSmrg	if ((src_pitch == line_len) && (src_pitch == dst_pitch)) {
33fda9279dSmrg		memcpy(dst, src, line_len*height);
34fda9279dSmrg	} else {
35fda9279dSmrg		while (height--) {
36fda9279dSmrg			memcpy(dst, src, line_len);
37fda9279dSmrg			src += src_pitch;
38fda9279dSmrg			dst += dst_pitch;
39fda9279dSmrg		}
40fda9279dSmrg	}
41fda9279dSmrg
42fda9279dSmrg	return TRUE;
43fda9279dSmrg}
44fda9279dSmrg
45fda9279dSmrgBool
46fda9279dSmrgNVAccelM2MF(NVPtr pNv, int w, int h, int cpp, uint32_t srcoff, uint32_t dstoff,
47fda9279dSmrg	    struct nouveau_bo *src, int sd, int sp, int sh, int sx, int sy,
48fda9279dSmrg	    struct nouveau_bo *dst, int dd, int dp, int dh, int dx, int dy)
49fda9279dSmrg{
50fda9279dSmrg	if (pNv->ce_rect && pNv->ce_enabled)
51fda9279dSmrg		return pNv->ce_rect(pNv->ce_pushbuf, pNv->NvCopy, w, h, cpp,
52fda9279dSmrg				    src, srcoff, sd, sp, sh, sx, sy,
53fda9279dSmrg				    dst, dstoff, dd, dp, dh, dx, dy);
54fda9279dSmrg	else
55fda9279dSmrg	if (pNv->Architecture >= NV_KEPLER)
56fda9279dSmrg		return NVE0EXARectCopy(pNv, w, h, cpp,
57fda9279dSmrg				       src, srcoff, sd, sp, sh, sx, sy,
58fda9279dSmrg				       dst, dstoff, dd, dp, dh, dx, dy);
59fda9279dSmrg	else
60fda9279dSmrg	if (pNv->Architecture >= NV_FERMI)
61fda9279dSmrg		return NVC0EXARectM2MF(pNv, w, h, cpp,
62fda9279dSmrg				       src, srcoff, sd, sp, sh, sx, sy,
63fda9279dSmrg				       dst, dstoff, dd, dp, dh, dx, dy);
64fda9279dSmrg	else
65fda9279dSmrg	if (pNv->Architecture >= NV_TESLA)
66fda9279dSmrg		return NV50EXARectM2MF(pNv, w, h, cpp,
67fda9279dSmrg				       src, srcoff, sd, sp, sh, sx, sy,
68fda9279dSmrg				       dst, dstoff, dd, dp, dh, dx, dy);
69fda9279dSmrg	else
70fda9279dSmrg		return NV04EXARectM2MF(pNv, w, h, cpp,
71fda9279dSmrg				       src, srcoff, sd, sp, sh, sx, sy,
72fda9279dSmrg				       dst, dstoff, dd, dp, dh, dx, dy);
73fda9279dSmrg	return FALSE;
74fda9279dSmrg}
75fda9279dSmrg
76fda9279dSmrgstatic int
77fda9279dSmrgnouveau_exa_mark_sync(ScreenPtr pScreen)
78fda9279dSmrg{
79fda9279dSmrg	return 0;
80fda9279dSmrg}
81fda9279dSmrg
82fda9279dSmrgstatic void
83fda9279dSmrgnouveau_exa_wait_marker(ScreenPtr pScreen, int marker)
84fda9279dSmrg{
85fda9279dSmrg}
86fda9279dSmrg
87fda9279dSmrgstatic Bool
88fda9279dSmrgnouveau_exa_prepare_access(PixmapPtr ppix, int index)
89fda9279dSmrg{
90fda9279dSmrg	struct nouveau_bo *bo = nouveau_pixmap_bo(ppix);
91fda9279dSmrg	NVPtr pNv = NVPTR(xf86ScreenToScrn(ppix->drawable.pScreen));
92fda9279dSmrg
93fda9279dSmrg	if (nv50_style_tiled_pixmap(ppix) && !pNv->wfb_enabled)
94fda9279dSmrg		return FALSE;
95fda9279dSmrg	if (nouveau_bo_map(bo, NOUVEAU_BO_RDWR, pNv->client))
96fda9279dSmrg		return FALSE;
97fda9279dSmrg	ppix->devPrivate.ptr = bo->map;
98fda9279dSmrg	return TRUE;
99fda9279dSmrg}
100fda9279dSmrg
101fda9279dSmrgstatic void
102fda9279dSmrgnouveau_exa_finish_access(PixmapPtr ppix, int index)
103fda9279dSmrg{
104fda9279dSmrg}
105fda9279dSmrg
106fda9279dSmrgstatic Bool
107fda9279dSmrgnouveau_exa_pixmap_is_offscreen(PixmapPtr ppix)
108fda9279dSmrg{
109fda9279dSmrg	return nouveau_pixmap_bo(ppix) != NULL;
110fda9279dSmrg}
111fda9279dSmrg
112fda9279dSmrgstatic void *
113fda9279dSmrgnouveau_exa_create_pixmap(ScreenPtr pScreen, int width, int height, int depth,
114fda9279dSmrg			  int usage_hint, int bitsPerPixel, int *new_pitch)
115fda9279dSmrg{
116fda9279dSmrg	ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
117fda9279dSmrg	NVPtr pNv = NVPTR(scrn);
118fda9279dSmrg	struct nouveau_pixmap *nvpix;
119fda9279dSmrg	int ret;
120fda9279dSmrg
121fda9279dSmrg	if (!width || !height)
122fda9279dSmrg		return calloc(1, sizeof(*nvpix));
123fda9279dSmrg
124fda9279dSmrg	if (!pNv->exa_force_cp && pNv->dev->vram_size <= 32 * 1024 * 1024)
125fda9279dSmrg		return NULL;
126fda9279dSmrg
127fda9279dSmrg	nvpix = calloc(1, sizeof(*nvpix));
128fda9279dSmrg	if (!nvpix)
129fda9279dSmrg		return NULL;
130fda9279dSmrg
131fda9279dSmrg	ret = nouveau_allocate_surface(scrn, width, height, bitsPerPixel,
132fda9279dSmrg				       usage_hint, new_pitch, &nvpix->bo);
133fda9279dSmrg	if (!ret) {
134fda9279dSmrg		free(nvpix);
135fda9279dSmrg		return NULL;
136fda9279dSmrg	}
137fda9279dSmrg
138fda9279dSmrg#ifdef NOUVEAU_PIXMAP_SHARING
139fda9279dSmrg	if ((usage_hint & 0xffff) == CREATE_PIXMAP_USAGE_SHARED)
140fda9279dSmrg		nvpix->shared = TRUE;
141fda9279dSmrg#endif
142fda9279dSmrg
143fda9279dSmrg	return nvpix;
144fda9279dSmrg}
145fda9279dSmrg
146fda9279dSmrgstatic void
147fda9279dSmrgnouveau_exa_destroy_pixmap(ScreenPtr pScreen, void *priv)
148fda9279dSmrg{
149fda9279dSmrg	struct nouveau_pixmap *nvpix = priv;
150fda9279dSmrg
151fda9279dSmrg	if (!nvpix)
152fda9279dSmrg		return;
153fda9279dSmrg
154fda9279dSmrg	nouveau_bo_ref(NULL, &nvpix->bo);
155fda9279dSmrg	free(nvpix);
156fda9279dSmrg}
157fda9279dSmrg
158fda9279dSmrg#ifdef NOUVEAU_PIXMAP_SHARING
159fda9279dSmrgstatic Bool
16033adc6acSmrgnouveau_exa_share_pixmap_backing(PixmapPtr ppix, ScreenPtr secondary, void **handle_p)
161fda9279dSmrg{
162fda9279dSmrg	struct nouveau_bo *bo = nouveau_pixmap_bo(ppix);
163fda9279dSmrg	struct nouveau_pixmap *nvpix = nouveau_pixmap(ppix);
164fda9279dSmrg	int ret;
165fda9279dSmrg	int handle;
166fda9279dSmrg
167fda9279dSmrg	ret = nouveau_bo_set_prime(bo, &handle);
168fda9279dSmrg	if (ret != 0) {
169fda9279dSmrg		ErrorF("%s: ret is %d errno is %d\n", __func__, ret, errno);
170fda9279dSmrg		return FALSE;
171fda9279dSmrg	}
172fda9279dSmrg	nvpix->shared = TRUE;
173fda9279dSmrg	*handle_p = (void *)(long)handle;
174fda9279dSmrg	return TRUE;
175fda9279dSmrg}
176fda9279dSmrg
177fda9279dSmrgstatic Bool
178fda9279dSmrgnouveau_exa_set_shared_pixmap_backing(PixmapPtr ppix, void *handle)
179fda9279dSmrg{
180fda9279dSmrg	ScrnInfoPtr pScrn = xf86ScreenToScrn(ppix->drawable.pScreen);
181fda9279dSmrg	NVPtr pNv = NVPTR(pScrn);
182fda9279dSmrg	struct nouveau_bo *bo = nouveau_pixmap_bo(ppix);
183fda9279dSmrg	struct nouveau_pixmap *nvpix = nouveau_pixmap(ppix);
184fda9279dSmrg	int ret;
185fda9279dSmrg	int ihandle = (int)(long)(handle);
186fda9279dSmrg
187fda9279dSmrg	ret = nouveau_bo_prime_handle_ref(pNv->dev, ihandle, &bo);
188fda9279dSmrg	if (ret) {
189fda9279dSmrg		ErrorF("failed to get BO with handle %d\n", ihandle);
190fda9279dSmrg		return FALSE;
191fda9279dSmrg	}
192fda9279dSmrg	nvpix->bo = bo;
193fda9279dSmrg	nvpix->shared = TRUE;
194fda9279dSmrg	close(ihandle);
195fda9279dSmrg	return TRUE;
196fda9279dSmrg}
197fda9279dSmrg#endif
198fda9279dSmrg
199fda9279dSmrgbool
200fda9279dSmrgnv50_style_tiled_pixmap(PixmapPtr ppix)
201fda9279dSmrg{
202fda9279dSmrg	ScrnInfoPtr pScrn = xf86ScreenToScrn(ppix->drawable.pScreen);
203fda9279dSmrg	NVPtr pNv = NVPTR(pScrn);
204fda9279dSmrg
205fda9279dSmrg	return pNv->Architecture >= NV_TESLA &&
206fda9279dSmrg	       nouveau_pixmap_bo(ppix)->config.nv50.memtype;
207fda9279dSmrg}
208fda9279dSmrg
209fda9279dSmrgstatic int
210fda9279dSmrgnouveau_exa_scratch(NVPtr pNv, int size, struct nouveau_bo **pbo, int *off)
211fda9279dSmrg{
212fda9279dSmrg	struct nouveau_bo *bo;
213fda9279dSmrg	int ret;
214fda9279dSmrg
215fda9279dSmrg	if (!pNv->transfer ||
216fda9279dSmrg	     pNv->transfer->size <= pNv->transfer_offset + size) {
217fda9279dSmrg		ret = nouveau_bo_new(pNv->dev, NOUVEAU_BO_GART | NOUVEAU_BO_MAP,
218fda9279dSmrg				     0, NOUVEAU_ALIGN(size, 1 * 1024 * 1024),
219fda9279dSmrg				     NULL, &bo);
220fda9279dSmrg		if (ret != 0)
221fda9279dSmrg			return ret;
222fda9279dSmrg
223fda9279dSmrg		ret = nouveau_bo_map(bo, NOUVEAU_BO_RDWR, pNv->client);
224fda9279dSmrg		if (ret != 0) {
225fda9279dSmrg			nouveau_bo_ref(NULL, &bo);
226fda9279dSmrg			return ret;
227fda9279dSmrg		}
228fda9279dSmrg
229fda9279dSmrg		nouveau_bo_ref(bo, &pNv->transfer);
230fda9279dSmrg		nouveau_bo_ref(NULL, &bo);
231fda9279dSmrg		pNv->transfer_offset = 0;
232fda9279dSmrg	}
233fda9279dSmrg
234fda9279dSmrg	*off = pNv->transfer_offset;
235fda9279dSmrg	*pbo = pNv->transfer;
236fda9279dSmrg
237fda9279dSmrg	pNv->transfer_offset += size;
238fda9279dSmrg	return 0;
239fda9279dSmrg}
240fda9279dSmrg
241fda9279dSmrgstatic Bool
242fda9279dSmrgnouveau_exa_download_from_screen(PixmapPtr pspix, int x, int y, int w, int h,
243fda9279dSmrg				 char *dst, int dst_pitch)
244fda9279dSmrg{
245fda9279dSmrg	ScrnInfoPtr pScrn = xf86ScreenToScrn(pspix->drawable.pScreen);
246fda9279dSmrg	NVPtr pNv = NVPTR(pScrn);
247fda9279dSmrg	struct nouveau_bo *bo;
248fda9279dSmrg	int src_pitch, tmp_pitch, cpp, i;
249fda9279dSmrg	const char *src;
250fda9279dSmrg	Bool ret;
251fda9279dSmrg
252fda9279dSmrg	cpp = pspix->drawable.bitsPerPixel >> 3;
253fda9279dSmrg	src_pitch  = exaGetPixmapPitch(pspix);
254fda9279dSmrg	tmp_pitch = w * cpp;
255fda9279dSmrg
256fda9279dSmrg	while (h) {
257fda9279dSmrg		const int lines = (h > 2047) ? 2047 : h;
258fda9279dSmrg		struct nouveau_bo *tmp;
259fda9279dSmrg		int tmp_offset;
260fda9279dSmrg
261fda9279dSmrg		if (nouveau_exa_scratch(pNv, lines * tmp_pitch,
262fda9279dSmrg					&tmp, &tmp_offset))
263fda9279dSmrg			goto memcpy;
264fda9279dSmrg
265fda9279dSmrg		if (!NVAccelM2MF(pNv, w, lines, cpp, 0, tmp_offset,
266fda9279dSmrg				 nouveau_pixmap_bo(pspix), NOUVEAU_BO_VRAM,
267fda9279dSmrg				 src_pitch, pspix->drawable.height, x, y,
268fda9279dSmrg				 tmp, NOUVEAU_BO_GART, tmp_pitch,
269fda9279dSmrg				 lines, 0, 0))
270fda9279dSmrg			goto memcpy;
271fda9279dSmrg
272fda9279dSmrg		nouveau_bo_wait(tmp, NOUVEAU_BO_RD, pNv->client);
273fda9279dSmrg		if (dst_pitch == tmp_pitch) {
274fda9279dSmrg			memcpy(dst, tmp->map + tmp_offset, dst_pitch * lines);
275fda9279dSmrg			dst += dst_pitch * lines;
276fda9279dSmrg		} else {
277fda9279dSmrg			src = tmp->map + tmp_offset;
278fda9279dSmrg			for (i = 0; i < lines; i++) {
279fda9279dSmrg				memcpy(dst, src, tmp_pitch);
280fda9279dSmrg				src += tmp_pitch;
281fda9279dSmrg				dst += dst_pitch;
282fda9279dSmrg			}
283fda9279dSmrg		}
284fda9279dSmrg
285fda9279dSmrg		/* next! */
286fda9279dSmrg		h -= lines;
287fda9279dSmrg		y += lines;
288fda9279dSmrg	}
289fda9279dSmrg	return TRUE;
290fda9279dSmrg
291fda9279dSmrgmemcpy:
292fda9279dSmrg	bo = nouveau_pixmap_bo(pspix);
293fda9279dSmrg	if (nv50_style_tiled_pixmap(pspix))
294fda9279dSmrg		ErrorF("%s:%d - falling back to memcpy ignores tiling\n",
295fda9279dSmrg		       __func__, __LINE__);
296fda9279dSmrg
297fda9279dSmrg	if (nouveau_bo_map(bo, NOUVEAU_BO_RD, pNv->client))
298fda9279dSmrg		return FALSE;
299fda9279dSmrg	src = (char *)bo->map + (y * src_pitch) + (x * cpp);
300fda9279dSmrg	ret = NVAccelMemcpyRect(dst, src, h, dst_pitch, src_pitch, w*cpp);
301fda9279dSmrg	return ret;
302fda9279dSmrg}
303fda9279dSmrg
304fda9279dSmrgstatic Bool
305fda9279dSmrgnouveau_exa_upload_to_screen(PixmapPtr pdpix, int x, int y, int w, int h,
306fda9279dSmrg			     char *src, int src_pitch)
307fda9279dSmrg{
308fda9279dSmrg	ScrnInfoPtr pScrn = xf86ScreenToScrn(pdpix->drawable.pScreen);
309fda9279dSmrg	NVPtr pNv = NVPTR(pScrn);
310fda9279dSmrg	int dst_pitch, tmp_pitch, cpp, i;
311fda9279dSmrg	struct nouveau_bo *bo;
312fda9279dSmrg	char *dst;
313fda9279dSmrg	Bool ret;
314fda9279dSmrg
315fda9279dSmrg	cpp = pdpix->drawable.bitsPerPixel >> 3;
316fda9279dSmrg	dst_pitch  = exaGetPixmapPitch(pdpix);
317fda9279dSmrg	tmp_pitch = w * cpp;
318fda9279dSmrg
319fda9279dSmrg	/* try hostdata transfer */
320fda9279dSmrg	if (w * h * cpp < 16*1024) /* heuristic */
321fda9279dSmrg	{
322fda9279dSmrg		if (pNv->Architecture < NV_TESLA) {
323fda9279dSmrg			if (NV04EXAUploadIFC(pScrn, src, src_pitch, pdpix,
324fda9279dSmrg					     x, y, w, h, cpp)) {
325fda9279dSmrg				return TRUE;
326fda9279dSmrg			}
327fda9279dSmrg		} else
328fda9279dSmrg		if (pNv->Architecture < NV_FERMI) {
329fda9279dSmrg			if (NV50EXAUploadSIFC(src, src_pitch, pdpix,
330fda9279dSmrg					      x, y, w, h, cpp)) {
331fda9279dSmrg				return TRUE;
332fda9279dSmrg			}
333fda9279dSmrg		} else {
334fda9279dSmrg			if (NVC0EXAUploadSIFC(src, src_pitch, pdpix,
335fda9279dSmrg					      x, y, w, h, cpp)) {
336fda9279dSmrg				return TRUE;
337fda9279dSmrg			}
338fda9279dSmrg		}
339fda9279dSmrg	}
340fda9279dSmrg
341fda9279dSmrg	while (h) {
342fda9279dSmrg		const int lines = (h > 2047) ? 2047 : h;
343fda9279dSmrg		struct nouveau_bo *tmp;
344fda9279dSmrg		int tmp_offset;
345fda9279dSmrg
346fda9279dSmrg		if (nouveau_exa_scratch(pNv, lines * tmp_pitch,
347fda9279dSmrg					&tmp, &tmp_offset))
348fda9279dSmrg			goto memcpy;
349fda9279dSmrg
350fda9279dSmrg		if (src_pitch == tmp_pitch) {
351fda9279dSmrg			memcpy(tmp->map + tmp_offset, src, src_pitch * lines);
352fda9279dSmrg			src += src_pitch * lines;
353fda9279dSmrg		} else {
354fda9279dSmrg			dst = tmp->map + tmp_offset;
355fda9279dSmrg			for (i = 0; i < lines; i++) {
356fda9279dSmrg				memcpy(dst, src, tmp_pitch);
357fda9279dSmrg				src += src_pitch;
358fda9279dSmrg				dst += tmp_pitch;
359fda9279dSmrg			}
360fda9279dSmrg		}
361fda9279dSmrg
362fda9279dSmrg		if (!NVAccelM2MF(pNv, w, lines, cpp, tmp_offset, 0, tmp,
363fda9279dSmrg				 NOUVEAU_BO_GART, tmp_pitch, lines, 0, 0,
364fda9279dSmrg				 nouveau_pixmap_bo(pdpix), NOUVEAU_BO_VRAM,
365fda9279dSmrg				 dst_pitch, pdpix->drawable.height, x, y))
366fda9279dSmrg			goto memcpy;
367fda9279dSmrg
368fda9279dSmrg		/* next! */
369fda9279dSmrg		h -= lines;
370fda9279dSmrg		y += lines;
371fda9279dSmrg	}
372fda9279dSmrg
373fda9279dSmrg	return TRUE;
374fda9279dSmrg
375fda9279dSmrg	/* fallback to memcpy-based transfer */
376fda9279dSmrgmemcpy:
377fda9279dSmrg	bo = nouveau_pixmap_bo(pdpix);
378fda9279dSmrg	if (nv50_style_tiled_pixmap(pdpix))
379fda9279dSmrg		ErrorF("%s:%d - falling back to memcpy ignores tiling\n",
380fda9279dSmrg		       __func__, __LINE__);
381fda9279dSmrg
382fda9279dSmrg	if (nouveau_bo_map(bo, NOUVEAU_BO_WR, pNv->client))
383fda9279dSmrg		return FALSE;
384fda9279dSmrg	dst = (char *)bo->map + (y * dst_pitch) + (x * cpp);
385fda9279dSmrg	ret = NVAccelMemcpyRect(dst, src, h, dst_pitch, src_pitch, w*cpp);
386fda9279dSmrg	return ret;
387fda9279dSmrg}
388fda9279dSmrg
389fda9279dSmrgBool
390fda9279dSmrgnouveau_exa_pixmap_is_onscreen(PixmapPtr ppix)
391fda9279dSmrg{
392fda9279dSmrg	ScrnInfoPtr pScrn = xf86ScreenToScrn(ppix->drawable.pScreen);
393fda9279dSmrg
394fda9279dSmrg	if (pScrn->pScreen->GetScreenPixmap(pScrn->pScreen) == ppix)
395fda9279dSmrg		return TRUE;
396fda9279dSmrg
397fda9279dSmrg	return FALSE;
398fda9279dSmrg}
399fda9279dSmrg
400fda9279dSmrgstatic void
401fda9279dSmrgnouveau_exa_flush(ScrnInfoPtr pScrn)
402fda9279dSmrg{
403fda9279dSmrg	NVPtr pNv = NVPTR(pScrn);
404fda9279dSmrg	nouveau_pushbuf_kick(pNv->pushbuf, pNv->pushbuf->channel);
405fda9279dSmrg}
406fda9279dSmrg
407fda9279dSmrgBool
408fda9279dSmrgnouveau_exa_init(ScreenPtr pScreen)
409fda9279dSmrg{
410fda9279dSmrg	ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
411fda9279dSmrg	NVPtr pNv = NVPTR(pScrn);
412fda9279dSmrg	ExaDriverPtr exa;
413fda9279dSmrg
414fda9279dSmrg	if (!xf86LoadSubModule(pScrn, "exa"))
415fda9279dSmrg		return FALSE;
416fda9279dSmrg
417fda9279dSmrg	exa = exaDriverAlloc();
418fda9279dSmrg	if (!exa)
419fda9279dSmrg		return FALSE;
420fda9279dSmrg
421fda9279dSmrg	exa->exa_major = EXA_VERSION_MAJOR;
422fda9279dSmrg	exa->exa_minor = EXA_VERSION_MINOR;
423fda9279dSmrg	exa->flags = EXA_OFFSCREEN_PIXMAPS;
424fda9279dSmrg
425fda9279dSmrg#ifdef EXA_SUPPORTS_PREPARE_AUX
426fda9279dSmrg	exa->flags |= EXA_SUPPORTS_PREPARE_AUX;
427fda9279dSmrg#endif
428fda9279dSmrg
429fda9279dSmrg	exa->PixmapIsOffscreen = nouveau_exa_pixmap_is_offscreen;
430fda9279dSmrg	exa->PrepareAccess = nouveau_exa_prepare_access;
431fda9279dSmrg	exa->FinishAccess = nouveau_exa_finish_access;
432fda9279dSmrg
433fda9279dSmrg	exa->flags |= (EXA_HANDLES_PIXMAPS | EXA_MIXED_PIXMAPS);
434fda9279dSmrg	exa->pixmapOffsetAlign = 256;
435fda9279dSmrg	exa->pixmapPitchAlign = 64;
436fda9279dSmrg
437fda9279dSmrg	exa->CreatePixmap2 = nouveau_exa_create_pixmap;
438fda9279dSmrg	exa->DestroyPixmap = nouveau_exa_destroy_pixmap;
439fda9279dSmrg#ifdef NOUVEAU_PIXMAP_SHARING
440fda9279dSmrg	exa->SharePixmapBacking = nouveau_exa_share_pixmap_backing;
441fda9279dSmrg	exa->SetSharedPixmapBacking = nouveau_exa_set_shared_pixmap_backing;
442fda9279dSmrg#endif
443fda9279dSmrg
444fda9279dSmrg	if (pNv->Architecture >= NV_TESLA) {
445fda9279dSmrg		exa->maxX = 8192;
446fda9279dSmrg		exa->maxY = 8192;
447fda9279dSmrg	} else
448fda9279dSmrg	if (pNv->Architecture >= NV_ARCH_10) {
449fda9279dSmrg		exa->maxX = 4096;
450fda9279dSmrg		exa->maxY = 4096;
451fda9279dSmrg	} else {
452fda9279dSmrg		exa->maxX = 2048;
453fda9279dSmrg		exa->maxY = 2048;
454fda9279dSmrg	}
455fda9279dSmrg
456fda9279dSmrg	exa->MarkSync = nouveau_exa_mark_sync;
457fda9279dSmrg	exa->WaitMarker = nouveau_exa_wait_marker;
458fda9279dSmrg
459fda9279dSmrg	exa->DownloadFromScreen = nouveau_exa_download_from_screen;
460fda9279dSmrg	exa->UploadToScreen = nouveau_exa_upload_to_screen;
461fda9279dSmrg
462fda9279dSmrg	if (pNv->Architecture < NV_TESLA) {
463fda9279dSmrg		exa->PrepareCopy = NV04EXAPrepareCopy;
464fda9279dSmrg		exa->Copy = NV04EXACopy;
465fda9279dSmrg		exa->DoneCopy = NV04EXADoneCopy;
466fda9279dSmrg
467fda9279dSmrg		exa->PrepareSolid = NV04EXAPrepareSolid;
468fda9279dSmrg		exa->Solid = NV04EXASolid;
469fda9279dSmrg		exa->DoneSolid = NV04EXADoneSolid;
470fda9279dSmrg	} else
471fda9279dSmrg	if (pNv->Architecture < NV_FERMI) {
472fda9279dSmrg		exa->PrepareCopy = NV50EXAPrepareCopy;
473fda9279dSmrg		exa->Copy = NV50EXACopy;
474fda9279dSmrg		exa->DoneCopy = NV50EXADoneCopy;
475fda9279dSmrg
476fda9279dSmrg		exa->PrepareSolid = NV50EXAPrepareSolid;
477fda9279dSmrg		exa->Solid = NV50EXASolid;
478fda9279dSmrg		exa->DoneSolid = NV50EXADoneSolid;
479fda9279dSmrg	} else {
480fda9279dSmrg		exa->PrepareCopy = NVC0EXAPrepareCopy;
481fda9279dSmrg		exa->Copy        = NVC0EXACopy;
482fda9279dSmrg		exa->DoneCopy    = NVC0EXADoneCopy;
483fda9279dSmrg
484fda9279dSmrg		exa->PrepareSolid = NVC0EXAPrepareSolid;
485fda9279dSmrg		exa->Solid        = NVC0EXASolid;
486fda9279dSmrg		exa->DoneSolid    = NVC0EXADoneSolid;
487fda9279dSmrg	}
488fda9279dSmrg
489fda9279dSmrg	switch (pNv->Architecture) {
490fda9279dSmrg	case NV_ARCH_10:
491fda9279dSmrg	case NV_ARCH_20:
492fda9279dSmrg 		exa->CheckComposite   = NV10EXACheckComposite;
493fda9279dSmrg 		exa->PrepareComposite = NV10EXAPrepareComposite;
494fda9279dSmrg 		exa->Composite        = NV10EXAComposite;
495fda9279dSmrg 		exa->DoneComposite    = NV10EXADoneComposite;
496fda9279dSmrg		break;
497fda9279dSmrg	case NV_ARCH_30:
498fda9279dSmrg		exa->CheckComposite   = NV30EXACheckComposite;
499fda9279dSmrg		exa->PrepareComposite = NV30EXAPrepareComposite;
500fda9279dSmrg		exa->Composite        = NV30EXAComposite;
501fda9279dSmrg		exa->DoneComposite    = NV30EXADoneComposite;
502fda9279dSmrg		break;
503fda9279dSmrg	case NV_ARCH_40:
504fda9279dSmrg		exa->CheckComposite   = NV40EXACheckComposite;
505fda9279dSmrg		exa->PrepareComposite = NV40EXAPrepareComposite;
506fda9279dSmrg		exa->Composite        = NV40EXAComposite;
507fda9279dSmrg		exa->DoneComposite    = NV40EXADoneComposite;
508fda9279dSmrg		break;
509fda9279dSmrg	case NV_TESLA:
510fda9279dSmrg		exa->CheckComposite   = NV50EXACheckComposite;
511fda9279dSmrg		exa->PrepareComposite = NV50EXAPrepareComposite;
512fda9279dSmrg		exa->Composite        = NV50EXAComposite;
513fda9279dSmrg		exa->DoneComposite    = NV50EXADoneComposite;
514fda9279dSmrg		break;
515fda9279dSmrg	case NV_FERMI:
516fda9279dSmrg	case NV_KEPLER:
517cd34e0e1Smrg	case NV_MAXWELL:
518cd34e0e1Smrg	case NV_PASCAL:
519fda9279dSmrg		exa->CheckComposite   = NVC0EXACheckComposite;
520fda9279dSmrg		exa->PrepareComposite = NVC0EXAPrepareComposite;
521fda9279dSmrg		exa->Composite        = NVC0EXAComposite;
522fda9279dSmrg		exa->DoneComposite    = NVC0EXADoneComposite;
523fda9279dSmrg		break;
524fda9279dSmrg	default:
525fda9279dSmrg		break;
526fda9279dSmrg	}
527fda9279dSmrg
528fda9279dSmrg	if (!exaDriverInit(pScreen, exa))
529fda9279dSmrg		return FALSE;
530fda9279dSmrg
531fda9279dSmrg	pNv->EXADriverPtr = exa;
532fda9279dSmrg	pNv->Flush = nouveau_exa_flush;
533fda9279dSmrg	return TRUE;
534fda9279dSmrg}
535