1428d7b3dSmrg/*
2428d7b3dSmrg * Copyright © 2007-2011 Intel Corporation
3428d7b3dSmrg *
4428d7b3dSmrg * Permission is hereby granted, free of charge, to any person obtaining a
5428d7b3dSmrg * copy of this software and associated documentation files (the "Software"),
6428d7b3dSmrg * to deal in the Software without restriction, including without limitation
7428d7b3dSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8428d7b3dSmrg * and/or sell copies of the Software, and to permit persons to whom the
9428d7b3dSmrg * Software is furnished to do so, subject to the following conditions:
10428d7b3dSmrg *
11428d7b3dSmrg * The above copyright notice and this permission notice (including the next
12428d7b3dSmrg * paragraph) shall be included in all copies or substantial portions of the
13428d7b3dSmrg * Software.
14428d7b3dSmrg *
15428d7b3dSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16428d7b3dSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17428d7b3dSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18428d7b3dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19428d7b3dSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20428d7b3dSmrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21428d7b3dSmrg * SOFTWARE.
22428d7b3dSmrg *
23428d7b3dSmrg * Authors:
24428d7b3dSmrg *    Eric Anholt <eric@anholt.net>
25428d7b3dSmrg *    Chris Wilson <chris"chris-wilson.co.uk>
26428d7b3dSmrg *
27428d7b3dSmrg */
28428d7b3dSmrg
29428d7b3dSmrg#ifdef HAVE_CONFIG_H
30428d7b3dSmrg#include "config.h"
31428d7b3dSmrg#endif
32428d7b3dSmrg
33428d7b3dSmrg#include <sys/mman.h>
34428d7b3dSmrg#include <assert.h>
35428d7b3dSmrg
36428d7b3dSmrg#include "sna.h"
37428d7b3dSmrg#include "sna_reg.h"
38428d7b3dSmrg#include "gen7_render.h"
39428d7b3dSmrg
40428d7b3dSmrg#include "kgem_debug.h"
41428d7b3dSmrg
42428d7b3dSmrgstatic struct state {
43428d7b3dSmrg	struct vertex_buffer {
44428d7b3dSmrg		int handle;
45428d7b3dSmrg		void *base;
46428d7b3dSmrg		const char *ptr;
47428d7b3dSmrg		int pitch;
48428d7b3dSmrg
49428d7b3dSmrg		struct kgem_bo *current;
50428d7b3dSmrg	} vb[33];
51428d7b3dSmrg	struct vertex_elements {
52428d7b3dSmrg		int buffer;
53428d7b3dSmrg		int offset;
54428d7b3dSmrg		bool valid;
55428d7b3dSmrg		uint32_t type;
56428d7b3dSmrg		uint8_t swizzle[4];
57428d7b3dSmrg	} ve[33];
58428d7b3dSmrg	int num_ve;
59428d7b3dSmrg
60428d7b3dSmrg	struct dynamic_state {
61428d7b3dSmrg		struct kgem_bo *current;
62428d7b3dSmrg		void *base, *ptr;
63428d7b3dSmrg	} dynamic_state;
64428d7b3dSmrg} state;
65428d7b3dSmrg
66428d7b3dSmrgstatic void gen7_update_vertex_buffer(struct kgem *kgem, const uint32_t *data)
67428d7b3dSmrg{
68428d7b3dSmrg	uint32_t reloc = sizeof(uint32_t) * (&data[1] - kgem->batch);
69428d7b3dSmrg	struct kgem_bo *bo = NULL;
70428d7b3dSmrg	void *base, *ptr;
71428d7b3dSmrg	int i;
72428d7b3dSmrg
73428d7b3dSmrg	for (i = 0; i < kgem->nreloc; i++)
74428d7b3dSmrg		if (kgem->reloc[i].offset == reloc)
75428d7b3dSmrg			break;
76428d7b3dSmrg	assert(i < kgem->nreloc);
77428d7b3dSmrg	reloc = kgem->reloc[i].target_handle;
78428d7b3dSmrg
79428d7b3dSmrg	if (reloc == 0) {
80428d7b3dSmrg		base = kgem->batch;
81428d7b3dSmrg	} else {
82428d7b3dSmrg		list_for_each_entry(bo, &kgem->next_request->buffers, request)
83428d7b3dSmrg			if (bo->handle == reloc)
84428d7b3dSmrg				break;
85428d7b3dSmrg		assert(&bo->request != &kgem->next_request->buffers);
86428d7b3dSmrg		base = kgem_bo_map__debug(kgem, bo);
87428d7b3dSmrg	}
88428d7b3dSmrg	ptr = (char *)base + kgem->reloc[i].delta;
89428d7b3dSmrg
90428d7b3dSmrg	i = data[0] >> 26;
91428d7b3dSmrg
92428d7b3dSmrg	state.vb[i].current = bo;
93428d7b3dSmrg	state.vb[i].base = base;
94428d7b3dSmrg	state.vb[i].ptr = ptr;
95428d7b3dSmrg	state.vb[i].pitch = data[0] & 0x7ff;
96428d7b3dSmrg}
97428d7b3dSmrg
98428d7b3dSmrgstatic void gen7_update_dynamic_buffer(struct kgem *kgem, const uint32_t offset)
99428d7b3dSmrg{
100428d7b3dSmrg	uint32_t reloc = sizeof(uint32_t) * offset;
101428d7b3dSmrg	struct kgem_bo *bo = NULL;
102428d7b3dSmrg	void *base, *ptr;
103428d7b3dSmrg	int i;
104428d7b3dSmrg
105428d7b3dSmrg	if ((kgem->batch[offset] & 1) == 0)
106428d7b3dSmrg		return;
107428d7b3dSmrg
108428d7b3dSmrg	for (i = 0; i < kgem->nreloc; i++)
109428d7b3dSmrg		if (kgem->reloc[i].offset == reloc)
110428d7b3dSmrg			break;
111428d7b3dSmrg	if(i < kgem->nreloc) {
112428d7b3dSmrg		reloc = kgem->reloc[i].target_handle;
113428d7b3dSmrg
114428d7b3dSmrg		if (reloc == 0) {
115428d7b3dSmrg			base = kgem->batch;
116428d7b3dSmrg		} else {
117428d7b3dSmrg			list_for_each_entry(bo, &kgem->next_request->buffers, request)
118428d7b3dSmrg				if (bo->handle == reloc)
119428d7b3dSmrg					break;
120428d7b3dSmrg			assert(&bo->request != &kgem->next_request->buffers);
121428d7b3dSmrg			base = kgem_bo_map__debug(kgem, bo);
122428d7b3dSmrg		}
123428d7b3dSmrg		ptr = (char *)base + (kgem->reloc[i].delta & ~1);
124428d7b3dSmrg	} else {
125428d7b3dSmrg		bo = NULL;
126428d7b3dSmrg		base = NULL;
127428d7b3dSmrg		ptr = NULL;
128428d7b3dSmrg	}
129428d7b3dSmrg
130428d7b3dSmrg	state.dynamic_state.current = bo;
131428d7b3dSmrg	state.dynamic_state.base = base;
132428d7b3dSmrg	state.dynamic_state.ptr = ptr;
133428d7b3dSmrg}
134428d7b3dSmrg
135428d7b3dSmrgstatic uint32_t
136428d7b3dSmrgget_ve_component(uint32_t data, int component)
137428d7b3dSmrg{
138428d7b3dSmrg	return (data >> (16 + (3 - component) * 4)) & 0x7;
139428d7b3dSmrg}
140428d7b3dSmrg
141428d7b3dSmrgstatic void gen7_update_vertex_elements(struct kgem *kgem, int id, const uint32_t *data)
142428d7b3dSmrg{
143428d7b3dSmrg	state.ve[id].buffer = data[0] >> 26;
144428d7b3dSmrg	state.ve[id].valid = !!(data[0] & (1 << 25));
145428d7b3dSmrg	state.ve[id].type = (data[0] >> 16) & 0x1ff;
146428d7b3dSmrg	state.ve[id].offset = data[0] & 0x7ff;
147428d7b3dSmrg	state.ve[id].swizzle[0] = get_ve_component(data[1], 0);
148428d7b3dSmrg	state.ve[id].swizzle[1] = get_ve_component(data[1], 1);
149428d7b3dSmrg	state.ve[id].swizzle[2] = get_ve_component(data[1], 2);
150428d7b3dSmrg	state.ve[id].swizzle[3] = get_ve_component(data[1], 3);
151428d7b3dSmrg}
152428d7b3dSmrg
153428d7b3dSmrgstatic void gen7_update_sf_state(struct kgem *kgem, uint32_t *data)
154428d7b3dSmrg{
155428d7b3dSmrg	state.num_ve = 1 + ((data[1] >> 22) & 0x3f);
156428d7b3dSmrg}
157428d7b3dSmrg
158428d7b3dSmrgstatic void vertices_sint16_out(const struct vertex_elements *ve, const int16_t *v, int max)
159428d7b3dSmrg{
160428d7b3dSmrg	int c;
161428d7b3dSmrg
162428d7b3dSmrg	ErrorF("(");
163428d7b3dSmrg	for (c = 0; c < max; c++) {
164428d7b3dSmrg		switch (ve->swizzle[c]) {
165428d7b3dSmrg		case 0: ErrorF("#"); break;
166428d7b3dSmrg		case 1: ErrorF("%d", v[c]); break;
167428d7b3dSmrg		case 2: ErrorF("0.0"); break;
168428d7b3dSmrg		case 3: ErrorF("1.0"); break;
169428d7b3dSmrg		case 4: ErrorF("0x1"); break;
170428d7b3dSmrg		case 5: break;
171428d7b3dSmrg		default: ErrorF("?");
172428d7b3dSmrg		}
173428d7b3dSmrg		if (c < 3)
174428d7b3dSmrg			ErrorF(", ");
175428d7b3dSmrg	}
176428d7b3dSmrg	for (; c < 4; c++) {
177428d7b3dSmrg		switch (ve->swizzle[c]) {
178428d7b3dSmrg		case 0: ErrorF("#"); break;
179428d7b3dSmrg		case 1: ErrorF("1.0"); break;
180428d7b3dSmrg		case 2: ErrorF("0.0"); break;
181428d7b3dSmrg		case 3: ErrorF("1.0"); break;
182428d7b3dSmrg		case 4: ErrorF("0x1"); break;
183428d7b3dSmrg		case 5: break;
184428d7b3dSmrg		default: ErrorF("?");
185428d7b3dSmrg		}
186428d7b3dSmrg		if (c < 3)
187428d7b3dSmrg			ErrorF(", ");
188428d7b3dSmrg	}
189428d7b3dSmrg	ErrorF(")");
190428d7b3dSmrg}
191428d7b3dSmrg
192428d7b3dSmrgstatic void vertices_float_out(const struct vertex_elements *ve, const float *f, int max)
193428d7b3dSmrg{
194428d7b3dSmrg	int c, o;
195428d7b3dSmrg
196428d7b3dSmrg	ErrorF("(");
197428d7b3dSmrg	for (c = o = 0; c < 4 && o < max; c++) {
198428d7b3dSmrg		switch (ve->swizzle[c]) {
199428d7b3dSmrg		case 0: ErrorF("#"); break;
200428d7b3dSmrg		case 1: ErrorF("%f", f[o++]); break;
201428d7b3dSmrg		case 2: ErrorF("0.0"); break;
202428d7b3dSmrg		case 3: ErrorF("1.0"); break;
203428d7b3dSmrg		case 4: ErrorF("0x1"); break;
204428d7b3dSmrg		case 5: break;
205428d7b3dSmrg		default: ErrorF("?");
206428d7b3dSmrg		}
207428d7b3dSmrg		if (c < 3)
208428d7b3dSmrg			ErrorF(", ");
209428d7b3dSmrg	}
210428d7b3dSmrg	for (; c < 4; c++) {
211428d7b3dSmrg		switch (ve->swizzle[c]) {
212428d7b3dSmrg		case 0: ErrorF("#"); break;
213428d7b3dSmrg		case 1: ErrorF("1.0"); break;
214428d7b3dSmrg		case 2: ErrorF("0.0"); break;
215428d7b3dSmrg		case 3: ErrorF("1.0"); break;
216428d7b3dSmrg		case 4: ErrorF("0x1"); break;
217428d7b3dSmrg		case 5: break;
218428d7b3dSmrg		default: ErrorF("?");
219428d7b3dSmrg		}
220428d7b3dSmrg		if (c < 3)
221428d7b3dSmrg			ErrorF(", ");
222428d7b3dSmrg	}
223428d7b3dSmrg	ErrorF(")");
224428d7b3dSmrg}
225428d7b3dSmrg
226428d7b3dSmrgstatic void ve_out(const struct vertex_elements *ve, const void *ptr)
227428d7b3dSmrg{
228428d7b3dSmrg	switch (ve->type) {
229428d7b3dSmrg	case GEN7_SURFACEFORMAT_R32_FLOAT:
230428d7b3dSmrg		vertices_float_out(ve, ptr, 1);
231428d7b3dSmrg		break;
232428d7b3dSmrg	case GEN7_SURFACEFORMAT_R32G32_FLOAT:
233428d7b3dSmrg		vertices_float_out(ve, ptr, 2);
234428d7b3dSmrg		break;
235428d7b3dSmrg	case GEN7_SURFACEFORMAT_R32G32B32_FLOAT:
236428d7b3dSmrg		vertices_float_out(ve, ptr, 3);
237428d7b3dSmrg		break;
238428d7b3dSmrg	case GEN7_SURFACEFORMAT_R32G32B32A32_FLOAT:
239428d7b3dSmrg		vertices_float_out(ve, ptr, 4);
240428d7b3dSmrg		break;
241428d7b3dSmrg	case GEN7_SURFACEFORMAT_R16_SINT:
242428d7b3dSmrg		vertices_sint16_out(ve, ptr, 1);
243428d7b3dSmrg		break;
244428d7b3dSmrg	case GEN7_SURFACEFORMAT_R16G16_SINT:
245428d7b3dSmrg		vertices_sint16_out(ve, ptr, 2);
246428d7b3dSmrg		break;
247428d7b3dSmrg	case GEN7_SURFACEFORMAT_R16G16B16A16_SINT:
248428d7b3dSmrg		vertices_sint16_out(ve, ptr, 4);
249428d7b3dSmrg		break;
250428d7b3dSmrg	case GEN7_SURFACEFORMAT_R16_SSCALED:
251428d7b3dSmrg		vertices_sint16_out(ve, ptr, 1);
252428d7b3dSmrg		break;
253428d7b3dSmrg	case GEN7_SURFACEFORMAT_R16G16_SSCALED:
254428d7b3dSmrg		vertices_sint16_out(ve, ptr, 2);
255428d7b3dSmrg		break;
256428d7b3dSmrg	case GEN7_SURFACEFORMAT_R16G16B16A16_SSCALED:
257428d7b3dSmrg		vertices_sint16_out(ve, ptr, 4);
258428d7b3dSmrg		break;
259428d7b3dSmrg	}
260428d7b3dSmrg}
261428d7b3dSmrg
262428d7b3dSmrgstatic void indirect_vertex_out(struct kgem *kgem, uint32_t v)
263428d7b3dSmrg{
264428d7b3dSmrg	int i = 1;
265428d7b3dSmrg
266428d7b3dSmrg	do {
267428d7b3dSmrg		const struct vertex_elements *ve = &state.ve[i];
268428d7b3dSmrg		const struct vertex_buffer *vb = &state.vb[ve->buffer];
269428d7b3dSmrg		const void *ptr = vb->ptr + v * vb->pitch + ve->offset;
270428d7b3dSmrg
271428d7b3dSmrg		if (!ve->valid)
272428d7b3dSmrg			continue;
273428d7b3dSmrg
274428d7b3dSmrg		ve_out(ve, ptr);
275428d7b3dSmrg
276428d7b3dSmrg		while (++i <= state.num_ve && !state.ve[i].valid)
277428d7b3dSmrg			;
278428d7b3dSmrg
279428d7b3dSmrg		if (i <= state.num_ve)
280428d7b3dSmrg			ErrorF(", ");
281428d7b3dSmrg	} while (i <= state.num_ve);
282428d7b3dSmrg}
283428d7b3dSmrg
284428d7b3dSmrgstatic void primitive_out(struct kgem *kgem, uint32_t *data)
285428d7b3dSmrg{
286428d7b3dSmrg	int n;
287428d7b3dSmrg
288428d7b3dSmrg	assert((data[0] & (1<<15)) == 0); /* XXX index buffers */
289428d7b3dSmrg
290428d7b3dSmrg	for (n = 0; n < data[2]; n++) {
291428d7b3dSmrg		int v = data[3] + n;
292428d7b3dSmrg		ErrorF("	[%d:%d] = ", n, v);
293428d7b3dSmrg		indirect_vertex_out(kgem, v);
294428d7b3dSmrg		ErrorF("\n");
295428d7b3dSmrg	}
296428d7b3dSmrg}
297428d7b3dSmrg
298428d7b3dSmrgstatic void finish_state(struct kgem *kgem)
299428d7b3dSmrg{
300428d7b3dSmrg	memset(&state, 0, sizeof(state));
301428d7b3dSmrg}
302428d7b3dSmrg
303428d7b3dSmrgstatic void
304428d7b3dSmrgstate_base_out(uint32_t *data, uint32_t offset, unsigned int index,
305428d7b3dSmrg	       const char *name)
306428d7b3dSmrg{
307428d7b3dSmrg    if (data[index] & 1)
308428d7b3dSmrg	kgem_debug_print(data, offset, index,
309428d7b3dSmrg		  "%s state base address 0x%08x\n",
310428d7b3dSmrg		  name, data[index] & ~1);
311428d7b3dSmrg    else
312428d7b3dSmrg	kgem_debug_print(data, offset, index,
313428d7b3dSmrg		  "%s state base not updated\n",
314428d7b3dSmrg		  name);
315428d7b3dSmrg}
316428d7b3dSmrg
317428d7b3dSmrgstatic void
318428d7b3dSmrgstate_max_out(uint32_t *data, uint32_t offset, unsigned int index,
319428d7b3dSmrg	      const char *name)
320428d7b3dSmrg{
321428d7b3dSmrg	if (data[index] == 1)
322428d7b3dSmrg		kgem_debug_print(data, offset, index,
323428d7b3dSmrg			  "%s state upper bound disabled\n", name);
324428d7b3dSmrg	else if (data[index] & 1)
325428d7b3dSmrg		kgem_debug_print(data, offset, index,
326428d7b3dSmrg			  "%s state upper bound 0x%08x\n",
327428d7b3dSmrg			  name, data[index] & ~1);
328428d7b3dSmrg	else
329428d7b3dSmrg		kgem_debug_print(data, offset, index,
330428d7b3dSmrg			  "%s state upper bound not updated\n",
331428d7b3dSmrg			  name);
332428d7b3dSmrg}
333428d7b3dSmrg
334428d7b3dSmrgstatic const char *
335428d7b3dSmrgget_965_surfacetype(unsigned int surfacetype)
336428d7b3dSmrg{
337428d7b3dSmrg	switch (surfacetype) {
338428d7b3dSmrg	case 0: return "1D";
339428d7b3dSmrg	case 1: return "2D";
340428d7b3dSmrg	case 2: return "3D";
341428d7b3dSmrg	case 3: return "CUBE";
342428d7b3dSmrg	case 4: return "BUFFER";
343428d7b3dSmrg	case 7: return "NULL";
344428d7b3dSmrg	default: return "unknown";
345428d7b3dSmrg	}
346428d7b3dSmrg}
347428d7b3dSmrg
348428d7b3dSmrgstatic const char *
349428d7b3dSmrgget_965_depthformat(unsigned int depthformat)
350428d7b3dSmrg{
351428d7b3dSmrg	switch (depthformat) {
352428d7b3dSmrg	case 0: return "s8_z24float";
353428d7b3dSmrg	case 1: return "z32float";
354428d7b3dSmrg	case 2: return "z24s8";
355428d7b3dSmrg	case 5: return "z16";
356428d7b3dSmrg	default: return "unknown";
357428d7b3dSmrg	}
358428d7b3dSmrg}
359428d7b3dSmrg
360428d7b3dSmrgstatic const char *
361428d7b3dSmrgget_element_component(uint32_t data, int component)
362428d7b3dSmrg{
363428d7b3dSmrg	uint32_t component_control = (data >> (16 + (3 - component) * 4)) & 0x7;
364428d7b3dSmrg
365428d7b3dSmrg	switch (component_control) {
366428d7b3dSmrg	case 0:
367428d7b3dSmrg		return "nostore";
368428d7b3dSmrg	case 1:
369428d7b3dSmrg		switch (component) {
370428d7b3dSmrg		case 0: return "X";
371428d7b3dSmrg		case 1: return "Y";
372428d7b3dSmrg		case 2: return "Z";
373428d7b3dSmrg		case 3: return "W";
374428d7b3dSmrg		default: return "fail";
375428d7b3dSmrg		}
376428d7b3dSmrg	case 2:
377428d7b3dSmrg		return "0.0";
378428d7b3dSmrg	case 3:
379428d7b3dSmrg		return "1.0";
380428d7b3dSmrg	case 4:
381428d7b3dSmrg		return "0x1";
382428d7b3dSmrg	case 5:
383428d7b3dSmrg		return "VID";
384428d7b3dSmrg	default:
385428d7b3dSmrg		return "fail";
386428d7b3dSmrg	}
387428d7b3dSmrg}
388428d7b3dSmrg
389428d7b3dSmrgstatic const char *
390428d7b3dSmrgget_prim_type(uint32_t data)
391428d7b3dSmrg{
392428d7b3dSmrg	uint32_t primtype = data & 0x1f;
393428d7b3dSmrg
394428d7b3dSmrg	switch (primtype) {
395428d7b3dSmrg	case 0x01: return "point list";
396428d7b3dSmrg	case 0x02: return "line list";
397428d7b3dSmrg	case 0x03: return "line strip";
398428d7b3dSmrg	case 0x04: return "tri list";
399428d7b3dSmrg	case 0x05: return "tri strip";
400428d7b3dSmrg	case 0x06: return "tri fan";
401428d7b3dSmrg	case 0x07: return "quad list";
402428d7b3dSmrg	case 0x08: return "quad strip";
403428d7b3dSmrg	case 0x09: return "line list adj";
404428d7b3dSmrg	case 0x0a: return "line strip adj";
405428d7b3dSmrg	case 0x0b: return "tri list adj";
406428d7b3dSmrg	case 0x0c: return "tri strip adj";
407428d7b3dSmrg	case 0x0d: return "tri strip reverse";
408428d7b3dSmrg	case 0x0e: return "polygon";
409428d7b3dSmrg	case 0x0f: return "rect list";
410428d7b3dSmrg	case 0x10: return "line loop";
411428d7b3dSmrg	case 0x11: return "point list bf";
412428d7b3dSmrg	case 0x12: return "line strip cont";
413428d7b3dSmrg	case 0x13: return "line strip bf";
414428d7b3dSmrg	case 0x14: return "line strip cont bf";
415428d7b3dSmrg	case 0x15: return "tri fan no stipple";
416428d7b3dSmrg	default: return "fail";
417428d7b3dSmrg	}
418428d7b3dSmrg}
419428d7b3dSmrg
420428d7b3dSmrgstruct reloc {
421428d7b3dSmrg	struct kgem_bo *bo;
422428d7b3dSmrg	void *base;
423428d7b3dSmrg};
424428d7b3dSmrg
425428d7b3dSmrgstatic void *
426428d7b3dSmrgget_reloc(struct kgem *kgem,
427428d7b3dSmrg	  void *base, const uint32_t *reloc,
428428d7b3dSmrg	  struct reloc *r)
429428d7b3dSmrg{
430428d7b3dSmrg	uint32_t delta = *reloc;
431428d7b3dSmrg
432428d7b3dSmrg	memset(r, 0, sizeof(*r));
433428d7b3dSmrg
434428d7b3dSmrg	if (base == 0) {
435428d7b3dSmrg		uint32_t handle = sizeof(uint32_t) * (reloc - kgem->batch);
436428d7b3dSmrg		struct kgem_bo *bo = NULL;
437428d7b3dSmrg		int i;
438428d7b3dSmrg
439428d7b3dSmrg		for (i = 0; i < kgem->nreloc; i++)
440428d7b3dSmrg			if (kgem->reloc[i].offset == handle)
441428d7b3dSmrg				break;
442428d7b3dSmrg		assert(i < kgem->nreloc);
443428d7b3dSmrg		handle = kgem->reloc[i].target_handle;
444428d7b3dSmrg		delta = kgem->reloc[i].delta;
445428d7b3dSmrg
446428d7b3dSmrg		if (handle == 0) {
447428d7b3dSmrg			base = kgem->batch;
448428d7b3dSmrg		} else {
449428d7b3dSmrg			list_for_each_entry(bo, &kgem->next_request->buffers, request)
450428d7b3dSmrg				if (bo->handle == handle)
451428d7b3dSmrg					break;
452428d7b3dSmrg			assert(&bo->request != &kgem->next_request->buffers);
453428d7b3dSmrg			base = kgem_bo_map__debug(kgem, bo);
454428d7b3dSmrg			r->bo = bo;
455428d7b3dSmrg			r->base = base;
456428d7b3dSmrg		}
457428d7b3dSmrg	}
458428d7b3dSmrg
459428d7b3dSmrg	return (char *)base + (delta & ~3);
460428d7b3dSmrg}
461428d7b3dSmrg
462428d7b3dSmrgstatic const char *
463428d7b3dSmrggen7_filter_to_string(uint32_t filter)
464428d7b3dSmrg{
465428d7b3dSmrg	switch (filter) {
466428d7b3dSmrg	default:
467428d7b3dSmrg	case GEN7_MAPFILTER_NEAREST: return "nearest";
468428d7b3dSmrg	case GEN7_MAPFILTER_LINEAR: return "linear";
469428d7b3dSmrg	}
470428d7b3dSmrg}
471428d7b3dSmrg
472428d7b3dSmrgstatic const char *
473428d7b3dSmrggen7_repeat_to_string(uint32_t repeat)
474428d7b3dSmrg{
475428d7b3dSmrg	switch (repeat) {
476428d7b3dSmrg	default:
477428d7b3dSmrg	case GEN7_TEXCOORDMODE_CLAMP_BORDER: return "border";
478428d7b3dSmrg	case GEN7_TEXCOORDMODE_WRAP: return "wrap";
479428d7b3dSmrg	case GEN7_TEXCOORDMODE_CLAMP: return "clamp";
480428d7b3dSmrg	case GEN7_TEXCOORDMODE_MIRROR: return "mirror";
481428d7b3dSmrg	}
482428d7b3dSmrg}
483428d7b3dSmrg
484428d7b3dSmrgstatic void
485428d7b3dSmrggen7_decode_sampler_state(struct kgem *kgem, const uint32_t *reloc)
486428d7b3dSmrg{
487428d7b3dSmrg	const struct gen7_sampler_state *ss;
488428d7b3dSmrg	struct reloc r;
489428d7b3dSmrg	const char *min, *mag;
490428d7b3dSmrg	const char *s_wrap, *t_wrap, *r_wrap;
491428d7b3dSmrg
492428d7b3dSmrg	ss = get_reloc(kgem, state.dynamic_state.ptr, reloc, &r);
493428d7b3dSmrg
494428d7b3dSmrg	min = gen7_filter_to_string(ss->ss0.min_filter);
495428d7b3dSmrg	mag = gen7_filter_to_string(ss->ss0.mag_filter);
496428d7b3dSmrg
497428d7b3dSmrg	s_wrap = gen7_repeat_to_string(ss->ss3.s_wrap_mode);
498428d7b3dSmrg	t_wrap = gen7_repeat_to_string(ss->ss3.t_wrap_mode);
499428d7b3dSmrg	r_wrap = gen7_repeat_to_string(ss->ss3.r_wrap_mode);
500428d7b3dSmrg
501428d7b3dSmrg	ErrorF("  Sampler 0:\n");
502428d7b3dSmrg	ErrorF("    filter: min=%s, mag=%s\n", min, mag);
503428d7b3dSmrg	ErrorF("    wrap: s=%s, t=%s, r=%s\n", s_wrap, t_wrap, r_wrap);
504428d7b3dSmrg
505428d7b3dSmrg	ss++;
506428d7b3dSmrg	min = gen7_filter_to_string(ss->ss0.min_filter);
507428d7b3dSmrg	mag = gen7_filter_to_string(ss->ss0.mag_filter);
508428d7b3dSmrg
509428d7b3dSmrg	s_wrap = gen7_repeat_to_string(ss->ss3.s_wrap_mode);
510428d7b3dSmrg	t_wrap = gen7_repeat_to_string(ss->ss3.t_wrap_mode);
511428d7b3dSmrg	r_wrap = gen7_repeat_to_string(ss->ss3.r_wrap_mode);
512428d7b3dSmrg
513428d7b3dSmrg	ErrorF("  Sampler 1:\n");
514428d7b3dSmrg	ErrorF("    filter: min=%s, mag=%s\n", min, mag);
515428d7b3dSmrg	ErrorF("    wrap: s=%s, t=%s, r=%s\n", s_wrap, t_wrap, r_wrap);
516428d7b3dSmrg}
517428d7b3dSmrg
518428d7b3dSmrgstatic const char *
519428d7b3dSmrggen7_blend_factor_to_string(uint32_t v)
520428d7b3dSmrg{
521428d7b3dSmrg	switch (v) {
522428d7b3dSmrg#define C(x) case GEN7_BLENDFACTOR_##x: return #x;
523428d7b3dSmrg		C(ONE);
524428d7b3dSmrg		C(SRC_COLOR);
525428d7b3dSmrg		C(SRC_ALPHA);
526428d7b3dSmrg		C(DST_ALPHA);
527428d7b3dSmrg		C(DST_COLOR);
528428d7b3dSmrg		C(SRC_ALPHA_SATURATE);
529428d7b3dSmrg		C(CONST_COLOR);
530428d7b3dSmrg		C(CONST_ALPHA);
531428d7b3dSmrg		C(SRC1_COLOR);
532428d7b3dSmrg		C(SRC1_ALPHA);
533428d7b3dSmrg		C(ZERO);
534428d7b3dSmrg		C(INV_SRC_COLOR);
535428d7b3dSmrg		C(INV_SRC_ALPHA);
536428d7b3dSmrg		C(INV_DST_ALPHA);
537428d7b3dSmrg		C(INV_DST_COLOR);
538428d7b3dSmrg		C(INV_CONST_COLOR);
539428d7b3dSmrg		C(INV_CONST_ALPHA);
540428d7b3dSmrg		C(INV_SRC1_COLOR);
541428d7b3dSmrg		C(INV_SRC1_ALPHA);
542428d7b3dSmrg#undef C
543428d7b3dSmrg	default: return "???";
544428d7b3dSmrg	}
545428d7b3dSmrg}
546428d7b3dSmrg
547428d7b3dSmrgstatic const char *
548428d7b3dSmrggen7_blend_function_to_string(uint32_t v)
549428d7b3dSmrg{
550428d7b3dSmrg	switch (v) {
551428d7b3dSmrg#define C(x) case GEN7_BLENDFUNCTION_##x: return #x;
552428d7b3dSmrg		C(ADD);
553428d7b3dSmrg		C(SUBTRACT);
554428d7b3dSmrg		C(REVERSE_SUBTRACT);
555428d7b3dSmrg		C(MIN);
556428d7b3dSmrg		C(MAX);
557428d7b3dSmrg#undef C
558428d7b3dSmrg	default: return "???";
559428d7b3dSmrg	}
560428d7b3dSmrg}
561428d7b3dSmrg
562428d7b3dSmrgstatic void
563428d7b3dSmrggen7_decode_blend(struct kgem *kgem, const uint32_t *reloc)
564428d7b3dSmrg{
565428d7b3dSmrg	const struct gen7_blend_state *blend;
566428d7b3dSmrg	struct reloc r;
567428d7b3dSmrg	const char *dst, *src;
568428d7b3dSmrg	const char *func;
569428d7b3dSmrg
570428d7b3dSmrg	blend = get_reloc(kgem, state.dynamic_state.ptr, reloc, &r);
571428d7b3dSmrg
572428d7b3dSmrg	dst = gen7_blend_factor_to_string(blend->blend0.dest_blend_factor);
573428d7b3dSmrg	src = gen7_blend_factor_to_string(blend->blend0.source_blend_factor);
574428d7b3dSmrg	func = gen7_blend_function_to_string(blend->blend0.blend_func);
575428d7b3dSmrg
576428d7b3dSmrg	ErrorF("  Blend (%s): function %s, src=%s, dst=%s\n",
577428d7b3dSmrg	       blend->blend0.blend_enable ? "enabled" : "disabled",
578428d7b3dSmrg	       func, src, dst);
579428d7b3dSmrg}
580428d7b3dSmrg
581428d7b3dSmrgint kgem_gen7_decode_3d(struct kgem *kgem, uint32_t offset)
582428d7b3dSmrg{
583428d7b3dSmrg	static const struct {
584428d7b3dSmrg		uint32_t opcode;
585428d7b3dSmrg		int min_len;
586428d7b3dSmrg		int max_len;
587428d7b3dSmrg		const char *name;
588428d7b3dSmrg	} opcodes[] = {
589428d7b3dSmrg		{ 0x6101, 6, 6, "STATE_BASE_ADDRESS" },
590428d7b3dSmrg		{ 0x6102, 2, 2 , "STATE_SIP" },
591428d7b3dSmrg		{ 0x6104, 1, 1, "3DSTATE_PIPELINE_SELECT" },
592428d7b3dSmrg		{ 0x780a, 3, 3, "3DSTATE_INDEX_BUFFER" },
593428d7b3dSmrg		{ 0x7900, 4, 4, "3DSTATE_DRAWING_RECTANGLE" },
594428d7b3dSmrg	};
595428d7b3dSmrg	uint32_t *data = kgem->batch + offset;
596428d7b3dSmrg	uint32_t op;
597428d7b3dSmrg	unsigned int len;
598428d7b3dSmrg	int i;
599428d7b3dSmrg	const char *name;
600428d7b3dSmrg
601428d7b3dSmrg	len = (data[0] & 0xff) + 2;
602428d7b3dSmrg	op = (data[0] & 0xffff0000) >> 16;
603428d7b3dSmrg	switch (op) {
604428d7b3dSmrg	case 0x6101:
605428d7b3dSmrg		i = 0;
606428d7b3dSmrg		kgem_debug_print(data, offset, i++, "STATE_BASE_ADDRESS\n");
607428d7b3dSmrg		assert(len == 10);
608428d7b3dSmrg
609428d7b3dSmrg		state_base_out(data, offset, i++, "general");
610428d7b3dSmrg		state_base_out(data, offset, i++, "surface");
611428d7b3dSmrg		state_base_out(data, offset, i++, "dynamic");
612428d7b3dSmrg		state_base_out(data, offset, i++, "indirect");
613428d7b3dSmrg		state_base_out(data, offset, i++, "instruction");
614428d7b3dSmrg
615428d7b3dSmrg		state_max_out(data, offset, i++, "general");
616428d7b3dSmrg		state_max_out(data, offset, i++, "dynamic");
617428d7b3dSmrg		state_max_out(data, offset, i++, "indirect");
618428d7b3dSmrg		state_max_out(data, offset, i++, "instruction");
619428d7b3dSmrg
620428d7b3dSmrg		gen7_update_dynamic_buffer(kgem, offset + 3);
621428d7b3dSmrg
622428d7b3dSmrg		return len;
623428d7b3dSmrg
624428d7b3dSmrg	case 0x7808:
625428d7b3dSmrg		assert((len - 1) % 4 == 0);
626428d7b3dSmrg		kgem_debug_print(data, offset, 0, "3DSTATE_VERTEX_BUFFERS\n");
627428d7b3dSmrg
628428d7b3dSmrg		for (i = 1; i < len;) {
629428d7b3dSmrg			gen7_update_vertex_buffer(kgem, data + i);
630428d7b3dSmrg
631428d7b3dSmrg			kgem_debug_print(data, offset, i, "buffer %d: %s, pitch %db\n",
632428d7b3dSmrg				  data[i] >> 26,
633428d7b3dSmrg				  data[i] & (1 << 20) ? "random" : "sequential",
634428d7b3dSmrg				  data[i] & 0x07ff);
635428d7b3dSmrg			i++;
636428d7b3dSmrg			kgem_debug_print(data, offset, i++, "buffer address\n");
637428d7b3dSmrg			kgem_debug_print(data, offset, i++, "max index\n");
638428d7b3dSmrg			kgem_debug_print(data, offset, i++, "mbz\n");
639428d7b3dSmrg		}
640428d7b3dSmrg		return len;
641428d7b3dSmrg
642428d7b3dSmrg	case 0x7809:
643428d7b3dSmrg		assert((len + 1) % 2 == 0);
644428d7b3dSmrg		kgem_debug_print(data, offset, 0, "3DSTATE_VERTEX_ELEMENTS\n");
645428d7b3dSmrg
646428d7b3dSmrg		for (i = 1; i < len;) {
647428d7b3dSmrg			gen7_update_vertex_elements(kgem, (i - 1)/2, data + i);
648428d7b3dSmrg
649428d7b3dSmrg			kgem_debug_print(data, offset, i, "buffer %d: %svalid, type 0x%04x, "
650428d7b3dSmrg				  "src offset 0x%04x bytes\n",
651428d7b3dSmrg				  data[i] >> 26,
652428d7b3dSmrg				  data[i] & (1 << 25) ? "" : "in",
653428d7b3dSmrg				  (data[i] >> 16) & 0x1ff,
654428d7b3dSmrg				  data[i] & 0x07ff);
655428d7b3dSmrg			i++;
656428d7b3dSmrg			kgem_debug_print(data, offset, i, "(%s, %s, %s, %s), "
657428d7b3dSmrg				  "dst offset 0x%02x bytes\n",
658428d7b3dSmrg				  get_element_component(data[i], 0),
659428d7b3dSmrg				  get_element_component(data[i], 1),
660428d7b3dSmrg				  get_element_component(data[i], 2),
661428d7b3dSmrg				  get_element_component(data[i], 3),
662428d7b3dSmrg				  (data[i] & 0xff) * 4);
663428d7b3dSmrg			i++;
664428d7b3dSmrg		}
665428d7b3dSmrg		return len;
666428d7b3dSmrg
667428d7b3dSmrg	case 0x780a:
668428d7b3dSmrg		assert(len == 3);
669428d7b3dSmrg		kgem_debug_print(data, offset, 0, "3DSTATE_INDEX_BUFFER\n");
670428d7b3dSmrg		kgem_debug_print(data, offset, 1, "beginning buffer address\n");
671428d7b3dSmrg		kgem_debug_print(data, offset, 2, "ending buffer address\n");
672428d7b3dSmrg		return len;
673428d7b3dSmrg
674428d7b3dSmrg	case 0x7b00:
675428d7b3dSmrg		assert(len == 7);
676428d7b3dSmrg		kgem_debug_print(data, offset, 0, "3DPRIMITIVE\n");
677428d7b3dSmrg		kgem_debug_print(data, offset, 1, "type %s, %s\n",
678428d7b3dSmrg			  get_prim_type(data[1]),
679428d7b3dSmrg			  (data[1] & (1 << 15)) ? "random" : "sequential");
680428d7b3dSmrg		kgem_debug_print(data, offset, 2, "vertex count\n");
681428d7b3dSmrg		kgem_debug_print(data, offset, 3, "start vertex\n");
682428d7b3dSmrg		kgem_debug_print(data, offset, 4, "instance count\n");
683428d7b3dSmrg		kgem_debug_print(data, offset, 5, "start instance\n");
684428d7b3dSmrg		kgem_debug_print(data, offset, 6, "index bias\n");
685428d7b3dSmrg		primitive_out(kgem, data);
686428d7b3dSmrg		return len;
687428d7b3dSmrg	}
688428d7b3dSmrg
689428d7b3dSmrg	/* For the rest, just dump the bytes */
690428d7b3dSmrg	name = NULL;
691428d7b3dSmrg	for (i = 0; i < ARRAY_SIZE(opcodes); i++)
692428d7b3dSmrg		if (op == opcodes[i].opcode) {
693428d7b3dSmrg			name = opcodes[i].name;
694428d7b3dSmrg			break;
695428d7b3dSmrg		}
696428d7b3dSmrg
697428d7b3dSmrg	len = (data[0] & 0xff) + 2;
698428d7b3dSmrg	if (name == NULL) {
699428d7b3dSmrg		kgem_debug_print(data, offset, 0, "unknown\n");
700428d7b3dSmrg	} else {
701428d7b3dSmrg		kgem_debug_print(data, offset, 0, "%s\n", opcodes[i].name);
702428d7b3dSmrg		if (opcodes[i].max_len > 1) {
703428d7b3dSmrg			assert(len >= opcodes[i].min_len &&
704428d7b3dSmrg					len <= opcodes[i].max_len);
705428d7b3dSmrg		}
706428d7b3dSmrg	}
707428d7b3dSmrg	for (i = 1; i < len; i++)
708428d7b3dSmrg		kgem_debug_print(data, offset, i, "dword %d\n", i);
709428d7b3dSmrg
710428d7b3dSmrg	return len;
711428d7b3dSmrg}
712428d7b3dSmrg
713428d7b3dSmrgvoid kgem_gen7_finish_state(struct kgem *kgem)
714428d7b3dSmrg{
715428d7b3dSmrg	finish_state(kgem);
716428d7b3dSmrg}
717