OSDN Git Service

ilo: add command parser
[android-x86/external-mesa.git] / src / gallium / drivers / ilo / ilo_cp.c
1 /*
2  * Mesa 3-D graphics library
3  *
4  * Copyright (C) 2012-2013 LunarG, Inc.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included
14  * in all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22  * DEALINGS IN THE SOFTWARE.
23  *
24  * Authors:
25  *    Chia-I Wu <olv@lunarg.com>
26  */
27
28 #include "intel_reg.h" /* for MI_xxx */
29 #include "intel_winsys.h"
30
31 #include "ilo_cp.h"
32
33 /* the size of the private space */
34 static const int ilo_cp_private = 2;
35
36 /**
37  * Dump the contents of the parser bo.  This must be called in a post-flush
38  * hook.
39  */
40 void
41 ilo_cp_dump(struct ilo_cp *cp)
42 {
43    ilo_printf("dumping %d bytes\n", cp->used * 4);
44    if (cp->used)
45       cp->winsys->decode_commands(cp->winsys, cp->bo, cp->used * 4);
46 }
47
48 /**
49  * Save the command parser state for rewind.
50  *
51  * Note that this cannot rewind a flush, and the caller must make sure
52  * that does not happend.
53  */
54 void
55 ilo_cp_setjmp(struct ilo_cp *cp, struct ilo_cp_jmp_buf *jmp)
56 {
57    jmp->id = pointer_to_intptr(cp->bo);
58
59    jmp->size = cp->size;
60    jmp->used = cp->used;
61    jmp->stolen = cp->stolen;
62    /* save reloc count to rewind ilo_cp_write_bo() */
63    jmp->reloc_count = cp->bo->get_reloc_count(cp->bo);
64 }
65
66 /**
67  * Rewind to the saved state.
68  */
69 void
70 ilo_cp_longjmp(struct ilo_cp *cp, const struct ilo_cp_jmp_buf *jmp)
71 {
72    if (jmp->id != pointer_to_intptr(cp->bo)) {
73       assert(!"invalid use of CP longjmp");
74       return;
75    }
76
77    cp->size = jmp->size;
78    cp->used = jmp->used;
79    cp->stolen = jmp->stolen;
80    cp->bo->clear_relocs(cp->bo, jmp->reloc_count);
81 }
82
83 /**
84  * Clear the parser buffer.
85  */
86 static void
87 ilo_cp_clear_buffer(struct ilo_cp *cp)
88 {
89    cp->cmd_cur = 0;
90    cp->cmd_end = 0;
91
92    cp->used = 0;
93    cp->stolen = 0;
94
95    /*
96     * Recalculate cp->size.  This is needed not only because cp->stolen is
97     * reset above, but also that we added cp->reserve_for_pre_flush and
98     * ilo_cp_private to cp->size in ilo_cp_flush().
99     */
100    cp->size = cp->bo_size - (cp->reserve_for_pre_flush + ilo_cp_private);
101 }
102
103 /**
104  * Add MI_BATCH_BUFFER_END to the private space of the parser buffer.
105  */
106 static void
107 ilo_cp_end_buffer(struct ilo_cp *cp)
108 {
109    /* make the private space available */
110    cp->size += ilo_cp_private;
111
112    assert(cp->used + 2 <= cp->size);
113
114    cp->ptr[cp->used++] = MI_BATCH_BUFFER_END;
115
116    /*
117     * From the Sandy Bridge PRM, volume 1 part 1, page 107:
118     *
119     *     "The batch buffer must be QWord aligned and a multiple of QWords in
120     *      length."
121     */
122    if (cp->used & 1)
123       cp->ptr[cp->used++] = MI_NOOP;
124 }
125
126 /**
127  * Upload the parser buffer to the bo.
128  */
129 static int
130 ilo_cp_upload_buffer(struct ilo_cp *cp)
131 {
132    int err;
133
134    err = cp->bo->pwrite(cp->bo, 0, cp->used * 4, cp->ptr);
135    if (likely(!err && cp->stolen)) {
136       const int offset = cp->bo_size - cp->stolen;
137
138       err = cp->bo->pwrite(cp->bo, offset * 4,
139             cp->stolen * 4, &cp->ptr[offset]);
140    }
141
142    return err;
143 }
144
145 /**
146  * Reallocate the parser bo.
147  */
148 static void
149 ilo_cp_realloc_bo(struct ilo_cp *cp)
150 {
151    struct intel_bo *bo;
152
153    /*
154     * allocate the new bo before unreferencing the old one so that they
155     * won't point at the same address, which is needed for jmpbuf
156     */
157    bo = cp->winsys->alloc_buffer(cp->winsys,
158          "batch buffer", cp->bo_size * 4, 0);
159    if (unlikely(!bo))
160       return;
161
162    if (cp->bo)
163       cp->bo->unreference(cp->bo);
164    cp->bo = bo;
165
166    if (!cp->sys) {
167       cp->bo->map(cp->bo, true);
168       cp->ptr = cp->bo->get_virtual(cp->bo);
169    }
170 }
171
172 /**
173  * Execute the parser bo.
174  */
175 static int
176 ilo_cp_exec_bo(struct ilo_cp *cp)
177 {
178    const bool do_exec = !(ilo_debug & ILO_DEBUG_NOHW);
179    unsigned long flags;
180    int err;
181
182    switch (cp->ring) {
183    case ILO_CP_RING_RENDER:
184       flags = INTEL_EXEC_RENDER;
185       break;
186    case ILO_CP_RING_BLT:
187       flags = INTEL_EXEC_BLT;
188       break;
189    default:
190       flags = 0;
191       break;
192    }
193
194    if (likely(do_exec))
195       err = cp->bo->exec(cp->bo, cp->used * 4, cp->hw_ctx, flags);
196    else
197       err = 0;
198
199    return err;
200 }
201
202 static void
203 ilo_cp_call_hook(struct ilo_cp *cp, enum ilo_cp_hook hook)
204 {
205    const bool no_implicit_flush = cp->no_implicit_flush;
206
207    if (!cp->hooks[hook].func)
208       return;
209
210    /* no implicit flush in hooks */
211    cp->no_implicit_flush = true;
212    cp->hooks[hook].func(cp, cp->hooks[hook].data);
213
214    cp->no_implicit_flush = no_implicit_flush;
215 }
216
217 /**
218  * Flush the command parser and execute the commands.  When the parser buffer
219  * is empty, the hooks are not invoked.
220  */
221 void
222 ilo_cp_flush(struct ilo_cp *cp)
223 {
224    int err;
225
226    /* sanity check */
227    assert(cp->bo_size == cp->size +
228          cp->reserve_for_pre_flush + ilo_cp_private + cp->stolen);
229
230    if (!cp->used) {
231       ilo_cp_clear_buffer(cp);
232       return;
233    }
234
235    /* make the reserved space available temporarily */
236    cp->size += cp->reserve_for_pre_flush;
237    ilo_cp_call_hook(cp, ILO_CP_HOOK_PRE_FLUSH);
238
239    ilo_cp_end_buffer(cp);
240
241    if (cp->sys) {
242       err = ilo_cp_upload_buffer(cp);
243       if (likely(!err))
244          err = ilo_cp_exec_bo(cp);
245    }
246    else {
247       cp->bo->unmap(cp->bo);
248       err = ilo_cp_exec_bo(cp);
249    }
250
251    if (likely(!err)) {
252       ilo_cp_call_hook(cp, ILO_CP_HOOK_POST_FLUSH);
253       ilo_cp_clear_buffer(cp);
254    }
255    else {
256       /* reset first so that post-flush hook knows nothing was executed */
257       ilo_cp_clear_buffer(cp);
258       ilo_cp_call_hook(cp, ILO_CP_HOOK_POST_FLUSH);
259    }
260
261    ilo_cp_realloc_bo(cp);
262    ilo_cp_call_hook(cp, ILO_CP_HOOK_NEW_BATCH);
263 }
264
265 /**
266  * Destroy the command parser.
267  */
268 void
269 ilo_cp_destroy(struct ilo_cp *cp)
270 {
271    if (cp->bo)
272       cp->bo->unreference(cp->bo);
273    if (cp->hw_ctx)
274       cp->winsys->destroy_context(cp->winsys, cp->hw_ctx);
275
276    FREE(cp->sys);
277    FREE(cp);
278 }
279
280 /**
281  * Create a command parser.
282  */
283 struct ilo_cp *
284 ilo_cp_create(struct intel_winsys *winsys, bool direct_map)
285 {
286    struct ilo_cp *cp;
287
288    cp = CALLOC_STRUCT(ilo_cp);
289    if (!cp)
290       return NULL;
291
292    cp->winsys = winsys;
293    cp->hw_ctx = winsys->create_context(winsys);
294
295    cp->ring = ILO_CP_RING_RENDER;
296    cp->no_implicit_flush = false;
297    cp->reserve_for_pre_flush = 0;
298
299    memset(cp->hooks, 0, sizeof(cp->hooks));
300
301    cp->bo_size = 8192;
302
303    if (!direct_map) {
304       cp->sys = MALLOC(cp->bo_size * 4);
305       if (!cp->sys) {
306          FREE(cp);
307          return NULL;
308       }
309
310       cp->ptr = cp->sys;
311    }
312
313    ilo_cp_realloc_bo(cp);
314    if (!cp->bo) {
315       FREE(cp->sys);
316       FREE(cp);
317       return NULL;
318    }
319
320    ilo_cp_clear_buffer(cp);
321
322    return cp;
323 }