10974d292Smrg/*
20974d292Smrg * Copyright 2005 Eric Anholt
30974d292Smrg * Copyright 2005 Benjamin Herrenschmidt
40974d292Smrg * Copyright 2008 Advanced Micro Devices, Inc.
50974d292Smrg * All Rights Reserved.
60974d292Smrg *
70974d292Smrg * Permission is hereby granted, free of charge, to any person obtaining a
80974d292Smrg * copy of this software and associated documentation files (the "Software"),
90974d292Smrg * to deal in the Software without restriction, including without limitation
100974d292Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
110974d292Smrg * and/or sell copies of the Software, and to permit persons to whom the
120974d292Smrg * Software is furnished to do so, subject to the following conditions:
130974d292Smrg *
140974d292Smrg * The above copyright notice and this permission notice (including the next
150974d292Smrg * paragraph) shall be included in all copies or substantial portions of the
160974d292Smrg * Software.
170974d292Smrg *
180974d292Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
190974d292Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
200974d292Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
210974d292Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
220974d292Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
230974d292Smrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
240974d292Smrg * SOFTWARE.
250974d292Smrg *
260974d292Smrg * Authors:
270974d292Smrg *    Eric Anholt <anholt@FreeBSD.org>
280974d292Smrg *    Zack Rusin <zrusin@trolltech.com>
290974d292Smrg *    Benjamin Herrenschmidt <benh@kernel.crashing.org>
300974d292Smrg *    Alex Deucher <alexander.deucher@amd.com>
310974d292Smrg *    Matthias Hopf <mhopf@suse.de>
320974d292Smrg */
330974d292Smrg#ifdef HAVE_CONFIG_H
340974d292Smrg#include "config.h"
350974d292Smrg#endif
360974d292Smrg
370974d292Smrg#include "radeon.h"
3843df4709Smrg#ifdef XF86DRI
3943df4709Smrg#include "radeon_drm.h"
4043df4709Smrg#endif
4143df4709Smrg#include "radeon_macros.h"
420974d292Smrg#include "radeon_probe.h"
430974d292Smrg#include "radeon_version.h"
440974d292Smrg#include "radeon_vbo.h"
450974d292Smrg
460974d292SmrgPixmapPtr
470974d292SmrgRADEONGetDrawablePixmap(DrawablePtr pDrawable)
480974d292Smrg{
490974d292Smrg    if (pDrawable->type == DRAWABLE_WINDOW)
500974d292Smrg	return pDrawable->pScreen->GetWindowPixmap((WindowPtr)pDrawable);
510974d292Smrg    else
520974d292Smrg	return (PixmapPtr)pDrawable;
530974d292Smrg}
540974d292Smrg
550974d292Smrgvoid RADEONVlineHelperClear(ScrnInfoPtr pScrn)
560974d292Smrg{
570974d292Smrg    RADEONInfoPtr info = RADEONPTR(pScrn);
580974d292Smrg    struct radeon_accel_state *accel_state = info->accel_state;
590974d292Smrg
600974d292Smrg    accel_state->vline_crtc = NULL;
610974d292Smrg    accel_state->vline_y1 = -1;
620974d292Smrg    accel_state->vline_y2 = 0;
630974d292Smrg}
640974d292Smrg
650974d292Smrgvoid RADEONVlineHelperSet(ScrnInfoPtr pScrn, int x1, int y1, int x2, int y2)
660974d292Smrg{
670974d292Smrg    RADEONInfoPtr info = RADEONPTR(pScrn);
680974d292Smrg    struct radeon_accel_state *accel_state = info->accel_state;
690974d292Smrg
7043df4709Smrg    accel_state->vline_crtc = radeon_pick_best_crtc(pScrn, x1, x2, y1, y2);
710974d292Smrg    if (accel_state->vline_y1 == -1)
720974d292Smrg	accel_state->vline_y1 = y1;
730974d292Smrg    if (y1 < accel_state->vline_y1)
740974d292Smrg	accel_state->vline_y1 = y1;
750974d292Smrg    if (y2 > accel_state->vline_y2)
760974d292Smrg	accel_state->vline_y2 = y2;
770974d292Smrg}
780974d292Smrg
790974d292SmrgBool RADEONValidPM(uint32_t pm, int bpp)
800974d292Smrg{
810974d292Smrg    uint8_t r, g, b, a;
820974d292Smrg    Bool ret = FALSE;
830974d292Smrg
840974d292Smrg    switch (bpp) {
850974d292Smrg    case 8:
860974d292Smrg	a = pm & 0xff;
870974d292Smrg	if ((a == 0) || (a == 0xff))
880974d292Smrg	    ret = TRUE;
890974d292Smrg	break;
900974d292Smrg    case 16:
910974d292Smrg	r = (pm >> 11) & 0x1f;
920974d292Smrg	g = (pm >> 5) & 0x3f;
930974d292Smrg	b = (pm >> 0) & 0x1f;
940974d292Smrg	if (((r == 0) || (r == 0x1f)) &&
950974d292Smrg	    ((g == 0) || (g == 0x3f)) &&
960974d292Smrg	    ((b == 0) || (b == 0x1f)))
970974d292Smrg	    ret = TRUE;
980974d292Smrg	break;
990974d292Smrg    case 32:
1000974d292Smrg	a = (pm >> 24) & 0xff;
1010974d292Smrg	r = (pm >> 16) & 0xff;
1020974d292Smrg	g = (pm >> 8) & 0xff;
1030974d292Smrg	b = (pm >> 0) & 0xff;
1040974d292Smrg	if (((a == 0) || (a == 0xff)) &&
1050974d292Smrg	    ((r == 0) || (r == 0xff)) &&
1060974d292Smrg	    ((g == 0) || (g == 0xff)) &&
1070974d292Smrg	    ((b == 0) || (b == 0xff)))
1080974d292Smrg	    ret = TRUE;
1090974d292Smrg	break;
1100974d292Smrg    default:
1110974d292Smrg	break;
1120974d292Smrg    }
1130974d292Smrg    return ret;
1140974d292Smrg}
1150974d292Smrg
1160974d292SmrgBool RADEONCheckBPP(int bpp)
1170974d292Smrg{
1180974d292Smrg	switch (bpp) {
1190974d292Smrg	case 8:
1200974d292Smrg	case 16:
1210974d292Smrg	case 32:
1220974d292Smrg		return TRUE;
1230974d292Smrg	default:
1240974d292Smrg		break;
1250974d292Smrg	}
1260974d292Smrg	return FALSE;
1270974d292Smrg}
1280974d292Smrg
12968105dcbSveegoPixmapPtr RADEONSolidPixmap(ScreenPtr pScreen, uint32_t solid)
13068105dcbSveego{
13143df4709Smrg    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
13243df4709Smrg    RADEONInfoPtr info = RADEONPTR(pScrn);
13368105dcbSveego    PixmapPtr pPix = pScreen->CreatePixmap(pScreen, 1, 1, 32, 0);
13443df4709Smrg
13568105dcbSveego    exaMoveInPixmap(pPix);
13668105dcbSveego
13743df4709Smrg#if defined(XF86DRM_MODE)
13843df4709Smrg    if (info->cs) {
13943df4709Smrg	struct radeon_bo *bo;
14043df4709Smrg
14143df4709Smrg	bo = radeon_get_pixmap_bo(pPix);
14243df4709Smrg
14343df4709Smrg	if (radeon_bo_map(bo, 1)) {
14443df4709Smrg	    pScreen->DestroyPixmap(pPix);
14543df4709Smrg	    return NULL;
14643df4709Smrg	}
14743df4709Smrg
14843df4709Smrg	memcpy(bo->ptr, &solid, 4);
14943df4709Smrg	radeon_bo_unmap(bo);
15068105dcbSveego
15143df4709Smrg	return pPix;
15243df4709Smrg    }
15343df4709Smrg#endif
15443df4709Smrg
15543df4709Smrg    if (!exaDrawableIsOffscreen(&pPix->drawable)) {
15668105dcbSveego	pScreen->DestroyPixmap(pPix);
15768105dcbSveego	return NULL;
15868105dcbSveego    }
15968105dcbSveego
16043df4709Smrg    /* XXX: Big hammer... */
16143df4709Smrg    info->accel_state->exa->WaitMarker(pScreen, info->accel_state->exaSyncMarker);
16243df4709Smrg    memcpy(info->FB + exaGetPixmapOffset(pPix), &solid, 4);
16368105dcbSveego
16468105dcbSveego    return pPix;
16568105dcbSveego}
16668105dcbSveego
16743df4709Smrgstatic Bool radeon_vb_get(ScrnInfoPtr pScrn)
16843df4709Smrg{
16943df4709Smrg    RADEONInfoPtr info = RADEONPTR(pScrn);
17043df4709Smrg    struct radeon_accel_state *accel_state = info->accel_state;
17143df4709Smrg
17243df4709Smrg    accel_state->vbo.vb_mc_addr = info->gartLocation + info->dri->bufStart +
17343df4709Smrg	(accel_state->ib->idx*accel_state->ib->total)+
17443df4709Smrg	(accel_state->ib->total / 2);
17543df4709Smrg    accel_state->vbo.vb_total = (accel_state->ib->total / 2);
17643df4709Smrg    accel_state->vbo.vb_ptr = (pointer)((char*)accel_state->ib->address +
17743df4709Smrg				    (accel_state->ib->total / 2));
17843df4709Smrg    accel_state->vbo.vb_offset = 0;
17943df4709Smrg    return TRUE;
18043df4709Smrg}
18143df4709Smrg
1820974d292Smrgint radeon_cp_start(ScrnInfoPtr pScrn)
1830974d292Smrg{
1840974d292Smrg    RADEONInfoPtr info = RADEONPTR(pScrn);
1850974d292Smrg    struct radeon_accel_state *accel_state = info->accel_state;
1860974d292Smrg
18743df4709Smrg#if defined(XF86DRM_MODE)
18843df4709Smrg    if (info->cs) {
18943df4709Smrg	if (CS_FULL(info->cs)) {
19043df4709Smrg	    radeon_cs_flush_indirect(pScrn);
19143df4709Smrg	}
19243df4709Smrg	accel_state->ib_reset_op = info->cs->cdw;
19343df4709Smrg    } else
19443df4709Smrg#endif
19543df4709Smrg    {
19643df4709Smrg	accel_state->ib = RADEONCPGetBuffer(pScrn);
19743df4709Smrg	if (!radeon_vb_get(pScrn)) {
19843df4709Smrg	    return -1;
19943df4709Smrg	}
2000974d292Smrg    }
201921a55d8Smrg    accel_state->vbo.vb_start_op = accel_state->vbo.vb_offset;
202921a55d8Smrg    accel_state->cbuf.vb_start_op = accel_state->cbuf.vb_offset;
2030974d292Smrg    return 0;
2040974d292Smrg}
2050974d292Smrg
206921a55d8Smrgvoid radeon_vb_no_space(ScrnInfoPtr pScrn,
207921a55d8Smrg			struct radeon_vbo_object *vbo,
208921a55d8Smrg			int vert_size)
2090974d292Smrg{
2100974d292Smrg    RADEONInfoPtr info = RADEONPTR(pScrn);
211921a55d8Smrg    struct radeon_accel_state *accel_state = info->accel_state;
2120974d292Smrg
21343df4709Smrg#if defined(XF86DRM_MODE)
21443df4709Smrg    if (info->cs) {
21543df4709Smrg	if (vbo->vb_bo) {
21643df4709Smrg	    if (vbo->vb_start_op != vbo->vb_offset) {
21743df4709Smrg		accel_state->finish_op(pScrn, vert_size);
21843df4709Smrg		accel_state->ib_reset_op = info->cs->cdw;
21943df4709Smrg	    }
2206322c902Smrg
22143df4709Smrg	    /* release the current VBO */
22243df4709Smrg	    radeon_vbo_put(pScrn, vbo);
22343df4709Smrg	}
22443df4709Smrg	/* get a new one */
22543df4709Smrg	radeon_vbo_get(pScrn, vbo);
22643df4709Smrg	return;
22743df4709Smrg    }
22843df4709Smrg#endif
22943df4709Smrg    if (vbo->vb_start_op != -1) {
23043df4709Smrg        accel_state->finish_op(pScrn, vert_size);
23143df4709Smrg        radeon_cp_start(pScrn);
2320974d292Smrg    }
2330974d292Smrg    return;
2340974d292Smrg}
2350974d292Smrg
23643df4709Smrg#if defined(XF86DRM_MODE)
2370974d292Smrgvoid radeon_ib_discard(ScrnInfoPtr pScrn)
2380974d292Smrg{
2390974d292Smrg    RADEONInfoPtr info = RADEONPTR(pScrn);
2400974d292Smrg    int ret;
2410974d292Smrg
2420974d292Smrg    if (info->accel_state->ib_reset_op) {
2430974d292Smrg        /* if we have data just reset the CS and ignore the operation */
2440974d292Smrg	info->cs->cdw = info->accel_state->ib_reset_op;
2450974d292Smrg	info->accel_state->ib_reset_op = 0;
2460974d292Smrg	goto out;
2470974d292Smrg    }
2480974d292Smrg
249921a55d8Smrg    info->accel_state->vbo.vb_offset = 0;
250921a55d8Smrg    info->accel_state->vbo.vb_start_op = -1;
251921a55d8Smrg    info->accel_state->cbuf.vb_offset = 0;
252921a55d8Smrg    info->accel_state->cbuf.vb_start_op = -1;
2530974d292Smrg
2540974d292Smrg    if (CS_FULL(info->cs)) {
2550974d292Smrg	radeon_cs_flush_indirect(pScrn);
2560974d292Smrg	return;
2570974d292Smrg    }
2580974d292Smrg    radeon_cs_erase(info->cs);
2590974d292Smrg    ret = radeon_cs_space_check_with_bo(info->cs,
260921a55d8Smrg					info->accel_state->vbo.vb_bo,
2610974d292Smrg					RADEON_GEM_DOMAIN_GTT, 0);
2620974d292Smrg    if (ret)
2630974d292Smrg	ErrorF("space check failed in flush\n");
2640974d292Smrg
265921a55d8Smrg    if (info->accel_state->cbuf.vb_bo) {
266921a55d8Smrg	ret = radeon_cs_space_check_with_bo(info->cs,
267921a55d8Smrg					    info->accel_state->cbuf.vb_bo,
268921a55d8Smrg					    RADEON_GEM_DOMAIN_GTT, 0);
269921a55d8Smrg	if (ret)
270921a55d8Smrg	    ErrorF("space check failed in flush\n");
271921a55d8Smrg    }
272921a55d8Smrg
2730974d292Smrg out:
2740974d292Smrg    if (info->dri2.enabled) {
2750974d292Smrg	info->accel_state->XInited3D = FALSE;
2760974d292Smrg	info->accel_state->engineMode = EXA_ENGINEMODE_UNKNOWN;
2770974d292Smrg    }
2780974d292Smrg
2790974d292Smrg}
28043df4709Smrg#endif
281