1fa225cbcSrjs/* -*- c-basic-offset: 4 -*- */
2fa225cbcSrjs/*
3fa225cbcSrjs * Copyright © 2006 Intel Corporation
4fa225cbcSrjs *
5fa225cbcSrjs * Permission is hereby granted, free of charge, to any person obtaining a
6fa225cbcSrjs * copy of this software and associated documentation files (the "Software"),
7fa225cbcSrjs * to deal in the Software without restriction, including without limitation
8fa225cbcSrjs * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9fa225cbcSrjs * and/or sell copies of the Software, and to permit persons to whom the
10fa225cbcSrjs * Software is furnished to do so, subject to the following conditions:
11fa225cbcSrjs *
12fa225cbcSrjs * The above copyright notice and this permission notice (including the next
13fa225cbcSrjs * paragraph) shall be included in all copies or substantial portions of the
14fa225cbcSrjs * Software.
15fa225cbcSrjs *
16fa225cbcSrjs * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17fa225cbcSrjs * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18fa225cbcSrjs * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19fa225cbcSrjs * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20fa225cbcSrjs * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21fa225cbcSrjs * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22fa225cbcSrjs * SOFTWARE.
23fa225cbcSrjs *
24fa225cbcSrjs * Authors:
25fa225cbcSrjs *    Eric Anholt <eric@anholt.net>
26fa225cbcSrjs *
27fa225cbcSrjs */
28fa225cbcSrjs
29fa225cbcSrjs#ifdef HAVE_CONFIG_H
30fa225cbcSrjs#include "config.h"
31fa225cbcSrjs#endif
32fa225cbcSrjs
33fa225cbcSrjs#include <assert.h>
34fa225cbcSrjs#include <stdlib.h>
35fa225cbcSrjs#include <errno.h>
36fa225cbcSrjs
37fa225cbcSrjs#include "xf86.h"
38fa225cbcSrjs#include "i830.h"
39fa225cbcSrjs#include "i830_ring.h"
40fa225cbcSrjs#include "i915_drm.h"
41fa225cbcSrjs
42fa225cbcSrjsstatic int
43fa225cbcSrjsintel_nondrm_exec(dri_bo *bo, unsigned int used, void *priv)
44fa225cbcSrjs{
45fa225cbcSrjs    ScrnInfoPtr pScrn = priv;
46fa225cbcSrjs    I830Ptr pI830 = I830PTR(pScrn);
47fa225cbcSrjs
48fa225cbcSrjs    BEGIN_LP_RING(4);
49fa225cbcSrjs    OUT_RING(MI_BATCH_BUFFER_START | (2 << 6));
50fa225cbcSrjs    OUT_RING(bo->offset);
51fa225cbcSrjs    OUT_RING(MI_NOOP);
52fa225cbcSrjs    OUT_RING(MI_NOOP);
53fa225cbcSrjs    ADVANCE_LP_RING();
54fa225cbcSrjs
55fa225cbcSrjs    return 0;
56fa225cbcSrjs}
57fa225cbcSrjs
58fa225cbcSrjsstatic int
59fa225cbcSrjsintel_nondrm_exec_i830(dri_bo *bo, unsigned int used, void *priv)
60fa225cbcSrjs{
61fa225cbcSrjs    ScrnInfoPtr pScrn = priv;
62fa225cbcSrjs    I830Ptr pI830 = I830PTR(pScrn);
63fa225cbcSrjs
64fa225cbcSrjs    BEGIN_LP_RING(4);
65fa225cbcSrjs    OUT_RING(MI_BATCH_BUFFER);
66fa225cbcSrjs    OUT_RING(bo->offset);
67fa225cbcSrjs    OUT_RING(bo->offset + pI830->batch_used - 4);
68fa225cbcSrjs    OUT_RING(MI_NOOP);
69fa225cbcSrjs    ADVANCE_LP_RING();
70fa225cbcSrjs
71fa225cbcSrjs    return 0;
72fa225cbcSrjs}
73fa225cbcSrjs
74fa225cbcSrjs/**
75fa225cbcSrjs * Creates a fence value representing a request to be passed.
76fa225cbcSrjs *
77fa225cbcSrjs * Stub implementation that should be avoided when DRM functions are available.
78fa225cbcSrjs */
79fa225cbcSrjsstatic unsigned int
80fa225cbcSrjsintel_nondrm_emit(void *priv)
81fa225cbcSrjs{
82fa225cbcSrjs    static unsigned int fence = 0;
83fa225cbcSrjs
84fa225cbcSrjs    /* Match DRM in not using half the range. The fake bufmgr relies on this. */
85fa225cbcSrjs    if (++fence >= 0x8000000)
86fa225cbcSrjs	fence = 1;
87fa225cbcSrjs
88fa225cbcSrjs    return fence;
89fa225cbcSrjs}
90fa225cbcSrjs
91fa225cbcSrjs/**
92fa225cbcSrjs * Waits on a fence representing a request to be passed.
93fa225cbcSrjs *
94fa225cbcSrjs * Stub implementation that should be avoided when DRM functions are available.
95fa225cbcSrjs */
96fa225cbcSrjsstatic void
97fa225cbcSrjsintel_nondrm_wait(unsigned int fence, void *priv)
98fa225cbcSrjs{
99fa225cbcSrjs    ScrnInfoPtr pScrn = priv;
100fa225cbcSrjs
101fa225cbcSrjs    i830_wait_ring_idle(pScrn);
102fa225cbcSrjs}
103fa225cbcSrjs
104fa225cbcSrjsstatic void
105fa225cbcSrjsintel_next_batch(ScrnInfoPtr pScrn)
106fa225cbcSrjs{
107fa225cbcSrjs    I830Ptr pI830 = I830PTR(pScrn);
108fa225cbcSrjs
109fa225cbcSrjs    /* The 865 has issues with larger-than-page-sized batch buffers. */
110fa225cbcSrjs    if (IS_I865G(pI830))
111fa225cbcSrjs	pI830->batch_bo = dri_bo_alloc(pI830->bufmgr, "batch", 4096, 4096);
112fa225cbcSrjs    else
113fa225cbcSrjs	pI830->batch_bo = dri_bo_alloc(pI830->bufmgr, "batch", 4096 * 4, 4096);
114fa225cbcSrjs
115fa225cbcSrjs    if (dri_bo_map(pI830->batch_bo, 1) != 0)
116fa225cbcSrjs	FatalError("Failed to map batchbuffer: %s\n", strerror(errno));
117fa225cbcSrjs
118fa225cbcSrjs    pI830->batch_used = 0;
119fa225cbcSrjs    pI830->batch_ptr = pI830->batch_bo->virtual;
120fa225cbcSrjs
121fa225cbcSrjs    /* If we are using DRI2, we don't know when another client has executed,
122fa225cbcSrjs     * so we have to reinitialize our 3D state per batch.
123fa225cbcSrjs     */
124fa225cbcSrjs    if (pI830->directRenderingType == DRI_DRI2)
125fa225cbcSrjs	pI830->last_3d = LAST_3D_OTHER;
126fa225cbcSrjs}
127fa225cbcSrjs
128fa225cbcSrjsvoid
129fa225cbcSrjsintel_batch_init(ScrnInfoPtr pScrn)
130fa225cbcSrjs{
131fa225cbcSrjs    I830Ptr pI830 = I830PTR(pScrn);
132fa225cbcSrjs
133fa225cbcSrjs    pI830->batch_emit_start = 0;
134fa225cbcSrjs    pI830->batch_emitting = 0;
135fa225cbcSrjs
136fa225cbcSrjs    intel_next_batch(pScrn);
137fa225cbcSrjs
138fa225cbcSrjs    if (!pI830->have_gem) {
139fa225cbcSrjs	if (IS_I830(pI830) || IS_845G(pI830)) {
140fa225cbcSrjs	    intel_bufmgr_fake_set_exec_callback(pI830->bufmgr,
141fa225cbcSrjs						intel_nondrm_exec_i830,
142fa225cbcSrjs						pScrn);
143fa225cbcSrjs	} else {
144fa225cbcSrjs	    intel_bufmgr_fake_set_exec_callback(pI830->bufmgr,
145fa225cbcSrjs						intel_nondrm_exec,
146fa225cbcSrjs						pScrn);
147fa225cbcSrjs	}
148fa225cbcSrjs	intel_bufmgr_fake_set_fence_callback(pI830->bufmgr,
149fa225cbcSrjs					     intel_nondrm_emit,
150fa225cbcSrjs					     intel_nondrm_wait,
151fa225cbcSrjs					     pScrn);
152fa225cbcSrjs    }
153fa225cbcSrjs}
154fa225cbcSrjs
155fa225cbcSrjsvoid
156fa225cbcSrjsintel_batch_teardown(ScrnInfoPtr pScrn)
157fa225cbcSrjs{
158fa225cbcSrjs    I830Ptr pI830 = I830PTR(pScrn);
159fa225cbcSrjs
160fa225cbcSrjs    if (pI830->batch_ptr != NULL) {
161fa225cbcSrjs	dri_bo_unmap(pI830->batch_bo);
162fa225cbcSrjs	pI830->batch_ptr = NULL;
163fa225cbcSrjs
164fa225cbcSrjs	dri_bo_unreference(pI830->batch_bo);
165fa225cbcSrjs	pI830->batch_bo = NULL;
166fa225cbcSrjs
167fa225cbcSrjs	dri_bo_unreference(pI830->last_batch_bo);
168fa225cbcSrjs	pI830->last_batch_bo = NULL;
169fa225cbcSrjs    }
170fa225cbcSrjs}
171fa225cbcSrjs
172fa225cbcSrjsvoid
173fa225cbcSrjsintel_batch_flush(ScrnInfoPtr pScrn, Bool flushed)
174fa225cbcSrjs{
175fa225cbcSrjs    I830Ptr pI830 = I830PTR(pScrn);
176fa225cbcSrjs    int ret;
177fa225cbcSrjs
178fa225cbcSrjs    if (pI830->batch_used == 0)
179fa225cbcSrjs	return;
180fa225cbcSrjs
181fa225cbcSrjs    /* If we're not using GEM, then emit a flush after each batch buffer */
182fa225cbcSrjs    if (!pI830->have_gem && !flushed) {
183fa225cbcSrjs	int flags = MI_WRITE_DIRTY_STATE | MI_INVALIDATE_MAP_CACHE;
184fa225cbcSrjs
185fa225cbcSrjs	if (IS_I965G(pI830))
186fa225cbcSrjs	    flags = 0;
187fa225cbcSrjs
188fa225cbcSrjs	*(uint32_t *)(pI830->batch_ptr + pI830->batch_used) = MI_FLUSH | flags;
189fa225cbcSrjs	pI830->batch_used += 4;
190fa225cbcSrjs    }
191fa225cbcSrjs
192fa225cbcSrjs    /* Emit a padding dword if we aren't going to be quad-word aligned. */
193fa225cbcSrjs    if ((pI830->batch_used & 4) == 0) {
194fa225cbcSrjs	*(uint32_t *)(pI830->batch_ptr + pI830->batch_used) = MI_NOOP;
195fa225cbcSrjs	pI830->batch_used += 4;
196fa225cbcSrjs    }
197fa225cbcSrjs
198fa225cbcSrjs    /* Mark the end of the batchbuffer. */
199fa225cbcSrjs    *(uint32_t *)(pI830->batch_ptr + pI830->batch_used) = MI_BATCH_BUFFER_END;
200fa225cbcSrjs    pI830->batch_used += 4;
201fa225cbcSrjs
202fa225cbcSrjs    dri_bo_unmap(pI830->batch_bo);
203fa225cbcSrjs    pI830->batch_ptr = NULL;
204fa225cbcSrjs
205fa225cbcSrjs    ret = dri_bo_exec(pI830->batch_bo, pI830->batch_used, NULL, 0, 0xffffffff);
206fa225cbcSrjs    if (ret != 0)
207fa225cbcSrjs	FatalError("Failed to submit batchbuffer: %s\n", strerror(-ret));
208fa225cbcSrjs
209fa225cbcSrjs    /* Save a ref to the last batch emitted, which we use for syncing
210fa225cbcSrjs     * in debug code.
211fa225cbcSrjs     */
212fa225cbcSrjs    dri_bo_unreference(pI830->last_batch_bo);
213fa225cbcSrjs    pI830->last_batch_bo = pI830->batch_bo;
214fa225cbcSrjs    pI830->batch_bo = NULL;
215fa225cbcSrjs
216fa225cbcSrjs    intel_next_batch(pScrn);
217fa225cbcSrjs
218fa225cbcSrjs    /* Mark that we need to flush whatever potential rendering we've done in the
219fa225cbcSrjs     * blockhandler.  We could set this less often, but it's probably not worth
220fa225cbcSrjs     * the work.
221fa225cbcSrjs     */
222fa225cbcSrjs    if (pI830->have_gem)
223fa225cbcSrjs	pI830->need_mi_flush = TRUE;
224fa225cbcSrjs
225fa225cbcSrjs    if (pI830->batch_flush_notify)
226fa225cbcSrjs	pI830->batch_flush_notify (pScrn);
227fa225cbcSrjs}
228fa225cbcSrjs
229fa225cbcSrjs/** Waits on the last emitted batchbuffer to be completed. */
230fa225cbcSrjsvoid
231fa225cbcSrjsintel_batch_wait_last(ScrnInfoPtr scrn)
232fa225cbcSrjs{
233fa225cbcSrjs    I830Ptr pI830 = I830PTR(scrn);
234fa225cbcSrjs
235fa225cbcSrjs    /* Map it CPU write, which guarantees it's done.  This is a completely
236fa225cbcSrjs     * non performance path, so we don't need anything better.
237fa225cbcSrjs     */
238fa225cbcSrjs    drm_intel_bo_map(pI830->last_batch_bo, TRUE);
239fa225cbcSrjs    drm_intel_bo_unmap(pI830->last_batch_bo);
240fa225cbcSrjs}
241fa225cbcSrjs
242