1428d7b3dSmrg/* -*- c-basic-offset: 4 -*- */
2428d7b3dSmrg/*
3428d7b3dSmrg * Copyright © 2006 Intel Corporation
4428d7b3dSmrg *
5428d7b3dSmrg * Permission is hereby granted, free of charge, to any person obtaining a
6428d7b3dSmrg * copy of this software and associated documentation files (the "Software"),
7428d7b3dSmrg * to deal in the Software without restriction, including without limitation
8428d7b3dSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9428d7b3dSmrg * and/or sell copies of the Software, and to permit persons to whom the
10428d7b3dSmrg * Software is furnished to do so, subject to the following conditions:
11428d7b3dSmrg *
12428d7b3dSmrg * The above copyright notice and this permission notice (including the next
13428d7b3dSmrg * paragraph) shall be included in all copies or substantial portions of the
14428d7b3dSmrg * Software.
15428d7b3dSmrg *
16428d7b3dSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17428d7b3dSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18428d7b3dSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19428d7b3dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20428d7b3dSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21428d7b3dSmrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22428d7b3dSmrg * SOFTWARE.
23428d7b3dSmrg *
24428d7b3dSmrg * Authors:
25428d7b3dSmrg *    Eric Anholt <eric@anholt.net>
26428d7b3dSmrg *
27428d7b3dSmrg */
28428d7b3dSmrg
29428d7b3dSmrg#ifdef HAVE_CONFIG_H
30428d7b3dSmrg#include "config.h"
31428d7b3dSmrg#endif
32428d7b3dSmrg
33428d7b3dSmrg#include <assert.h>
34428d7b3dSmrg#include <stdlib.h>
35428d7b3dSmrg#include <errno.h>
36428d7b3dSmrg
37428d7b3dSmrg#include "xorg-server.h"
38428d7b3dSmrg#include "xf86.h"
39428d7b3dSmrg#include "intel.h"
40428d7b3dSmrg#include "i830_reg.h"
41428d7b3dSmrg#include "i915_drm.h"
42428d7b3dSmrg#include "i965_reg.h"
43428d7b3dSmrg
44428d7b3dSmrg#include "intel_uxa.h"
45428d7b3dSmrg
46428d7b3dSmrg#define DUMP_BATCHBUFFERS NULL // "/tmp/i915-batchbuffers.dump"
47428d7b3dSmrg
48428d7b3dSmrgstatic void intel_end_vertex(intel_screen_private *intel)
49428d7b3dSmrg{
50428d7b3dSmrg	if (intel->vertex_bo) {
51428d7b3dSmrg		if (intel->vertex_used) {
52428d7b3dSmrg			dri_bo_subdata(intel->vertex_bo, 0, intel->vertex_used*4, intel->vertex_ptr);
53428d7b3dSmrg			intel->vertex_used = 0;
54428d7b3dSmrg		}
55428d7b3dSmrg
56428d7b3dSmrg		dri_bo_unreference(intel->vertex_bo);
57428d7b3dSmrg		intel->vertex_bo = NULL;
58428d7b3dSmrg	}
59428d7b3dSmrg
60428d7b3dSmrg	intel->vertex_id = 0;
61428d7b3dSmrg}
62428d7b3dSmrg
63428d7b3dSmrgvoid intel_next_vertex(intel_screen_private *intel)
64428d7b3dSmrg{
65428d7b3dSmrg	intel_end_vertex(intel);
66428d7b3dSmrg
67428d7b3dSmrg	intel->vertex_bo =
68428d7b3dSmrg		dri_bo_alloc(intel->bufmgr, "vertex", sizeof (intel->vertex_ptr), 4096);
69428d7b3dSmrg}
70428d7b3dSmrg
71428d7b3dSmrgstatic dri_bo *bo_alloc(ScrnInfoPtr scrn)
72428d7b3dSmrg{
73428d7b3dSmrg	intel_screen_private *intel = intel_get_screen_private(scrn);
74428d7b3dSmrg	int size = 4 * 4096;
75428d7b3dSmrg	/* The 865 has issues with larger-than-page-sized batch buffers. */
76428d7b3dSmrg	if (IS_I865G(intel))
77428d7b3dSmrg		size = 4096;
78428d7b3dSmrg	return dri_bo_alloc(intel->bufmgr, "batch", size, 4096);
79428d7b3dSmrg}
80428d7b3dSmrg
81428d7b3dSmrgstatic void intel_next_batch(ScrnInfoPtr scrn, int mode)
82428d7b3dSmrg{
83428d7b3dSmrg	intel_screen_private *intel = intel_get_screen_private(scrn);
84428d7b3dSmrg	dri_bo *tmp;
85428d7b3dSmrg
86428d7b3dSmrg	drm_intel_gem_bo_clear_relocs(intel->batch_bo, 0);
87428d7b3dSmrg
88428d7b3dSmrg	tmp = intel->last_batch_bo[mode];
89428d7b3dSmrg	intel->last_batch_bo[mode] = intel->batch_bo;
90428d7b3dSmrg	intel->batch_bo = tmp;
91428d7b3dSmrg
92428d7b3dSmrg	intel->batch_used = 0;
93428d7b3dSmrg
94428d7b3dSmrg	/* We don't know when another client has executed, so we have
95428d7b3dSmrg	 * to reinitialize our 3D state per batch.
96428d7b3dSmrg	 */
97428d7b3dSmrg	intel->last_3d = LAST_3D_OTHER;
98428d7b3dSmrg}
99428d7b3dSmrg
100428d7b3dSmrgvoid intel_batch_init(ScrnInfoPtr scrn)
101428d7b3dSmrg{
102428d7b3dSmrg	intel_screen_private *intel = intel_get_screen_private(scrn);
103428d7b3dSmrg
104428d7b3dSmrg	intel->batch_emit_start = 0;
105428d7b3dSmrg	intel->batch_emitting = 0;
106428d7b3dSmrg	intel->vertex_id = 0;
107428d7b3dSmrg
108428d7b3dSmrg	intel->last_batch_bo[0] = bo_alloc(scrn);
109428d7b3dSmrg	intel->last_batch_bo[1] = bo_alloc(scrn);
110428d7b3dSmrg
111428d7b3dSmrg	intel->batch_bo = bo_alloc(scrn);
112428d7b3dSmrg	intel->batch_used = 0;
113428d7b3dSmrg	intel->last_3d = LAST_3D_OTHER;
114428d7b3dSmrg}
115428d7b3dSmrg
116428d7b3dSmrgvoid intel_batch_teardown(ScrnInfoPtr scrn)
117428d7b3dSmrg{
118428d7b3dSmrg	intel_screen_private *intel = intel_get_screen_private(scrn);
119428d7b3dSmrg	int i;
120428d7b3dSmrg
121428d7b3dSmrg	for (i = 0; i < ARRAY_SIZE(intel->last_batch_bo); i++) {
122428d7b3dSmrg		if (intel->last_batch_bo[i] != NULL) {
123428d7b3dSmrg			dri_bo_unreference(intel->last_batch_bo[i]);
124428d7b3dSmrg			intel->last_batch_bo[i] = NULL;
125428d7b3dSmrg		}
126428d7b3dSmrg	}
127428d7b3dSmrg
128428d7b3dSmrg	if (intel->batch_bo != NULL) {
129428d7b3dSmrg		dri_bo_unreference(intel->batch_bo);
130428d7b3dSmrg		intel->batch_bo = NULL;
131428d7b3dSmrg	}
132428d7b3dSmrg
133428d7b3dSmrg	if (intel->vertex_bo) {
134428d7b3dSmrg		dri_bo_unreference(intel->vertex_bo);
135428d7b3dSmrg		intel->vertex_bo = NULL;
136428d7b3dSmrg	}
137428d7b3dSmrg
138428d7b3dSmrg	while (!list_is_empty(&intel->batch_pixmaps))
139428d7b3dSmrg		list_del(intel->batch_pixmaps.next);
140428d7b3dSmrg}
141428d7b3dSmrg
142428d7b3dSmrgstatic void intel_batch_do_flush(ScrnInfoPtr scrn)
143428d7b3dSmrg{
144428d7b3dSmrg	intel_screen_private *intel = intel_get_screen_private(scrn);
145428d7b3dSmrg	struct intel_uxa_pixmap *priv;
146428d7b3dSmrg
147428d7b3dSmrg	list_for_each_entry(priv, &intel->batch_pixmaps, batch)
148428d7b3dSmrg		priv->dirty = 0;
149428d7b3dSmrg}
150428d7b3dSmrg
151428d7b3dSmrgstatic void intel_emit_post_sync_nonzero_flush(ScrnInfoPtr scrn)
152428d7b3dSmrg{
153428d7b3dSmrg	intel_screen_private *intel = intel_get_screen_private(scrn);
154428d7b3dSmrg
155428d7b3dSmrg	/* keep this entire sequence of 3 PIPE_CONTROL cmds in one batch to
156428d7b3dSmrg	 * avoid upsetting the gpu. */
157428d7b3dSmrg	BEGIN_BATCH(3*4);
158428d7b3dSmrg	OUT_BATCH(BRW_PIPE_CONTROL | (4 - 2));
159428d7b3dSmrg	OUT_BATCH(BRW_PIPE_CONTROL_CS_STALL |
160428d7b3dSmrg		  BRW_PIPE_CONTROL_STALL_AT_SCOREBOARD);
161428d7b3dSmrg	OUT_BATCH(0); /* address */
162428d7b3dSmrg	OUT_BATCH(0); /* write data */
163428d7b3dSmrg
164428d7b3dSmrg	OUT_BATCH(BRW_PIPE_CONTROL | (4 - 2));
165428d7b3dSmrg	OUT_BATCH(BRW_PIPE_CONTROL_WRITE_QWORD);
166428d7b3dSmrg	OUT_RELOC(intel->wa_scratch_bo,
167428d7b3dSmrg		  I915_GEM_DOMAIN_INSTRUCTION, I915_GEM_DOMAIN_INSTRUCTION, 0);
168428d7b3dSmrg	OUT_BATCH(0); /* write data */
169428d7b3dSmrg
170428d7b3dSmrg	/* now finally the _real flush */
171428d7b3dSmrg	OUT_BATCH(BRW_PIPE_CONTROL | (4 - 2));
172428d7b3dSmrg	OUT_BATCH(BRW_PIPE_CONTROL_WC_FLUSH |
173428d7b3dSmrg		  BRW_PIPE_CONTROL_TC_FLUSH |
174428d7b3dSmrg		  BRW_PIPE_CONTROL_NOWRITE);
175428d7b3dSmrg	OUT_BATCH(0); /* write address */
176428d7b3dSmrg	OUT_BATCH(0); /* write data */
177428d7b3dSmrg	ADVANCE_BATCH();
178428d7b3dSmrg}
179428d7b3dSmrg
180428d7b3dSmrgvoid intel_batch_emit_flush(ScrnInfoPtr scrn)
181428d7b3dSmrg{
182428d7b3dSmrg	intel_screen_private *intel = intel_get_screen_private(scrn);
183428d7b3dSmrg	int flags;
184428d7b3dSmrg
185428d7b3dSmrg	assert (!intel->in_batch_atomic);
186428d7b3dSmrg
187428d7b3dSmrg	/* Big hammer, look to the pipelined flushes in future. */
188428d7b3dSmrg	if ((INTEL_INFO(intel)->gen >= 0100)) {
189428d7b3dSmrg		/* Only BLT supported */
190428d7b3dSmrg		BEGIN_BATCH_BLT(4);
191428d7b3dSmrg		OUT_BATCH(MI_FLUSH_DW | 2);
192428d7b3dSmrg		OUT_BATCH(0); /* address low */
193428d7b3dSmrg		OUT_BATCH(0); /* address high */
194428d7b3dSmrg		OUT_BATCH(0); /* dword data */
195428d7b3dSmrg		ADVANCE_BATCH();
196428d7b3dSmrg	} else if ((INTEL_INFO(intel)->gen >= 060)) {
197428d7b3dSmrg		if (intel->current_batch == BLT_BATCH) {
198428d7b3dSmrg			BEGIN_BATCH_BLT(4);
199428d7b3dSmrg			OUT_BATCH(MI_FLUSH_DW | 2);
200428d7b3dSmrg			OUT_BATCH(0); /* address */
201428d7b3dSmrg			OUT_BATCH(0); /* qword low */
202428d7b3dSmrg			OUT_BATCH(0); /* qword high */
203428d7b3dSmrg			ADVANCE_BATCH();
204428d7b3dSmrg		} else  {
205428d7b3dSmrg			if ((INTEL_INFO(intel)->gen == 060)) {
206428d7b3dSmrg				/* HW-Workaround for Sandybdrige */
207428d7b3dSmrg				intel_emit_post_sync_nonzero_flush(scrn);
208428d7b3dSmrg			} else {
209428d7b3dSmrg				BEGIN_BATCH(4);
210428d7b3dSmrg				OUT_BATCH(BRW_PIPE_CONTROL | (4 - 2));
211428d7b3dSmrg				OUT_BATCH(BRW_PIPE_CONTROL_WC_FLUSH |
212428d7b3dSmrg					  BRW_PIPE_CONTROL_TC_FLUSH |
213428d7b3dSmrg					  BRW_PIPE_CONTROL_NOWRITE);
214428d7b3dSmrg				OUT_BATCH(0); /* write address */
215428d7b3dSmrg				OUT_BATCH(0); /* write data */
216428d7b3dSmrg				ADVANCE_BATCH();
217428d7b3dSmrg			}
218428d7b3dSmrg		}
219428d7b3dSmrg	} else {
220428d7b3dSmrg		flags = MI_WRITE_DIRTY_STATE | MI_INVALIDATE_MAP_CACHE;
221428d7b3dSmrg		if (INTEL_INFO(intel)->gen >= 040)
222428d7b3dSmrg			flags = 0;
223428d7b3dSmrg
224428d7b3dSmrg		BEGIN_BATCH(1);
225428d7b3dSmrg		OUT_BATCH(MI_FLUSH | flags);
226428d7b3dSmrg		ADVANCE_BATCH();
227428d7b3dSmrg	}
228428d7b3dSmrg	intel_batch_do_flush(scrn);
229428d7b3dSmrg}
230428d7b3dSmrg
231428d7b3dSmrgvoid intel_batch_submit(ScrnInfoPtr scrn)
232428d7b3dSmrg{
233428d7b3dSmrg	intel_screen_private *intel = intel_get_screen_private(scrn);
234428d7b3dSmrg	int ret;
235428d7b3dSmrg
236428d7b3dSmrg	assert (!intel->in_batch_atomic);
237428d7b3dSmrg
238428d7b3dSmrg	if (intel->vertex_flush)
239428d7b3dSmrg		intel->vertex_flush(intel);
240428d7b3dSmrg	intel_end_vertex(intel);
241428d7b3dSmrg
242428d7b3dSmrg	if (intel->batch_flush)
243428d7b3dSmrg		intel->batch_flush(intel);
244428d7b3dSmrg
245428d7b3dSmrg	if (intel->batch_used == 0)
246428d7b3dSmrg		return;
247428d7b3dSmrg
248428d7b3dSmrg	/* Mark the end of the batchbuffer. */
249428d7b3dSmrg	OUT_BATCH(MI_BATCH_BUFFER_END);
250428d7b3dSmrg	/* Emit a padding dword if we aren't going to be quad-word aligned. */
251428d7b3dSmrg	if (intel->batch_used & 1)
252428d7b3dSmrg		OUT_BATCH(MI_NOOP);
253428d7b3dSmrg
254428d7b3dSmrg	if (DUMP_BATCHBUFFERS) {
255428d7b3dSmrg	    FILE *file = fopen(DUMP_BATCHBUFFERS, "a");
256428d7b3dSmrg	    if (file) {
257428d7b3dSmrg		fwrite (intel->batch_ptr, intel->batch_used*4, 1, file);
258428d7b3dSmrg		fclose(file);
259428d7b3dSmrg	    }
260428d7b3dSmrg	}
261428d7b3dSmrg
262428d7b3dSmrg	ret = dri_bo_subdata(intel->batch_bo, 0, intel->batch_used*4, intel->batch_ptr);
263428d7b3dSmrg	if (ret == 0) {
264428d7b3dSmrg		ret = drm_intel_bo_mrb_exec(intel->batch_bo,
265428d7b3dSmrg				intel->batch_used*4,
266428d7b3dSmrg				NULL, 0, 0xffffffff,
267428d7b3dSmrg				(HAS_BLT(intel) ?
268428d7b3dSmrg				 intel->current_batch:
269428d7b3dSmrg				 I915_EXEC_DEFAULT));
270428d7b3dSmrg	}
271428d7b3dSmrg
272428d7b3dSmrg	if (ret != 0) {
273428d7b3dSmrg		static int once;
274428d7b3dSmrg		if (!once) {
275428d7b3dSmrg			if (ret == -EIO) {
276428d7b3dSmrg				/* The GPU has hung and unlikely to recover by this point. */
277428d7b3dSmrg				xf86DrvMsg(scrn->scrnIndex, X_ERROR, "Detected a hung GPU, disabling acceleration.\n");
278428d7b3dSmrg				xf86DrvMsg(scrn->scrnIndex, X_ERROR, "When reporting this, please include i915_error_state from debugfs and the full dmesg.\n");
279428d7b3dSmrg			} else {
280428d7b3dSmrg				/* The driver is broken. */
281428d7b3dSmrg				xf86DrvMsg(scrn->scrnIndex, X_ERROR,
282428d7b3dSmrg					   "Failed to submit batch buffer, expect rendering corruption: %s.\n ",
283428d7b3dSmrg					   strerror(-ret));
284428d7b3dSmrg			}
285428d7b3dSmrg			uxa_set_force_fallback(xf86ScrnToScreen(scrn), TRUE);
286428d7b3dSmrg			intel->force_fallback = TRUE;
287428d7b3dSmrg			once = 1;
288428d7b3dSmrg		}
289428d7b3dSmrg	}
290428d7b3dSmrg
291428d7b3dSmrg	while (!list_is_empty(&intel->batch_pixmaps)) {
292428d7b3dSmrg		struct intel_uxa_pixmap *entry;
293428d7b3dSmrg
294428d7b3dSmrg		entry = list_first_entry(&intel->batch_pixmaps,
295428d7b3dSmrg					 struct intel_uxa_pixmap,
296428d7b3dSmrg					 batch);
297428d7b3dSmrg
298428d7b3dSmrg		entry->busy = -1;
299428d7b3dSmrg		entry->dirty = 0;
300428d7b3dSmrg		list_del(&entry->batch);
301428d7b3dSmrg	}
302428d7b3dSmrg
303428d7b3dSmrg	if (intel->debug_flush & DEBUG_FLUSH_WAIT)
304428d7b3dSmrg		drm_intel_bo_wait_rendering(intel->batch_bo);
305428d7b3dSmrg
306428d7b3dSmrg	intel_next_batch(scrn, intel->current_batch == I915_EXEC_BLT);
307428d7b3dSmrg
308428d7b3dSmrg	if (intel->batch_commit_notify)
309428d7b3dSmrg		intel->batch_commit_notify(intel);
310428d7b3dSmrg
311428d7b3dSmrg	intel->current_batch = 0;
312428d7b3dSmrg}
313428d7b3dSmrg
314428d7b3dSmrgvoid intel_uxa_debug_flush(ScrnInfoPtr scrn)
315428d7b3dSmrg{
316428d7b3dSmrg	intel_screen_private *intel = intel_get_screen_private(scrn);
317428d7b3dSmrg
318428d7b3dSmrg	if (intel->debug_flush & DEBUG_FLUSH_CACHES)
319428d7b3dSmrg		intel_batch_emit_flush(scrn);
320428d7b3dSmrg
321428d7b3dSmrg	if (intel->debug_flush & DEBUG_FLUSH_BATCHES)
322428d7b3dSmrg		intel_batch_submit(scrn);
323428d7b3dSmrg}
324