i915_gem_render_state.c revision 46470fc932ac8a0e8317a220b3f4ea4ed903338e
1/*
2 * Copyright © 2014 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 *
23 * Authors:
24 *    Mika Kuoppala <mika.kuoppala@intel.com>
25 *
26 */
27
28#include "i915_drv.h"
29#include "intel_renderstate.h"
30
31struct i915_render_state {
32	struct drm_i915_gem_object *obj;
33	unsigned long ggtt_offset;
34	void *batch;
35	u32 size;
36	u32 len;
37};
38
39static struct i915_render_state *render_state_alloc(struct drm_device *dev)
40{
41	struct i915_render_state *so;
42	struct page *page;
43	int ret;
44
45	so = kzalloc(sizeof(*so), GFP_KERNEL);
46	if (!so)
47		return ERR_PTR(-ENOMEM);
48
49	so->obj = i915_gem_alloc_object(dev, 4096);
50	if (so->obj == NULL) {
51		ret = -ENOMEM;
52		goto free;
53	}
54	so->size = 4096;
55
56	ret = i915_gem_obj_ggtt_pin(so->obj, 4096, 0);
57	if (ret)
58		goto free_gem;
59
60	BUG_ON(so->obj->pages->nents != 1);
61	page = sg_page(so->obj->pages->sgl);
62
63	so->batch = kmap(page);
64	if (!so->batch) {
65		ret = -ENOMEM;
66		goto unpin;
67	}
68
69	so->ggtt_offset = i915_gem_obj_ggtt_offset(so->obj);
70
71	return so;
72unpin:
73	i915_gem_object_ggtt_unpin(so->obj);
74free_gem:
75	drm_gem_object_unreference(&so->obj->base);
76free:
77	kfree(so);
78	return ERR_PTR(ret);
79}
80
81static void render_state_free(struct i915_render_state *so)
82{
83	kunmap(so->batch);
84	i915_gem_object_ggtt_unpin(so->obj);
85	drm_gem_object_unreference(&so->obj->base);
86	kfree(so);
87}
88
89static const struct intel_renderstate_rodata *
90render_state_get_rodata(struct drm_device *dev, const int gen)
91{
92	switch (gen) {
93	case 6:
94		return &gen6_null_state;
95	case 7:
96		return &gen7_null_state;
97	case 8:
98		return &gen8_null_state;
99	}
100
101	return NULL;
102}
103
104static int render_state_setup(const int gen,
105			      const struct intel_renderstate_rodata *rodata,
106			      struct i915_render_state *so)
107{
108	const u64 goffset = i915_gem_obj_ggtt_offset(so->obj);
109	u32 reloc_index = 0;
110	u32 * const d = so->batch;
111	unsigned int i = 0;
112	int ret;
113
114	if (!rodata || rodata->batch_items * 4 > so->size)
115		return -EINVAL;
116
117	ret = i915_gem_object_set_to_cpu_domain(so->obj, true);
118	if (ret)
119		return ret;
120
121	while (i < rodata->batch_items) {
122		u32 s = rodata->batch[i];
123
124		if (reloc_index < rodata->reloc_items &&
125		    i * 4  == rodata->reloc[reloc_index]) {
126
127			s += goffset & 0xffffffff;
128
129			/* We keep batch offsets max 32bit */
130			if (gen >= 8) {
131				if (i + 1 >= rodata->batch_items ||
132				    rodata->batch[i + 1] != 0)
133					return -EINVAL;
134
135				d[i] = s;
136				i++;
137				s = (goffset & 0xffffffff00000000ull) >> 32;
138			}
139
140			reloc_index++;
141		}
142
143		d[i] = s;
144		i++;
145	}
146
147	ret = i915_gem_object_set_to_gtt_domain(so->obj, false);
148	if (ret)
149		return ret;
150
151	if (rodata->reloc_items != reloc_index) {
152		DRM_ERROR("not all relocs resolved, %d out of %d\n",
153			  reloc_index, rodata->reloc_items);
154		return -EINVAL;
155	}
156
157	so->len = rodata->batch_items * 4;
158
159	return 0;
160}
161
162int i915_gem_render_state_init(struct intel_ring_buffer *ring)
163{
164	const int gen = INTEL_INFO(ring->dev)->gen;
165	struct i915_render_state *so;
166	const struct intel_renderstate_rodata *rodata;
167	int ret;
168
169	if (WARN_ON(ring->id != RCS))
170		return -ENOENT;
171
172	rodata = render_state_get_rodata(ring->dev, gen);
173	if (rodata == NULL)
174		return 0;
175
176	so = render_state_alloc(ring->dev);
177	if (IS_ERR(so))
178		return PTR_ERR(so);
179
180	ret = render_state_setup(gen, rodata, so);
181	if (ret)
182		goto out;
183
184	ret = ring->dispatch_execbuffer(ring,
185					i915_gem_obj_ggtt_offset(so->obj),
186					so->len,
187					I915_DISPATCH_SECURE);
188	if (ret)
189		goto out;
190
191	i915_vma_move_to_active(i915_gem_obj_to_ggtt(so->obj), ring);
192
193	ret = __i915_add_request(ring, NULL, so->obj, NULL);
194	/* __i915_add_request moves object to inactive if it fails */
195out:
196	render_state_free(so);
197	return ret;
198}
199