[965] Add batchbuffer dumping under INTEL_DEBUG=bat, like 915.
[mesa.git] / src / mesa / drivers / dri / i965 / intel_batchbuffer.c
1 /**************************************************************************
2 *
3 * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28 #include "imports.h"
29 #include "intel_batchbuffer.h"
30 #include "intel_ioctl.h"
31 #include "intel_decode.h"
32 #include "bufmgr.h"
33
34
35 static void intel_batchbuffer_reset( struct intel_batchbuffer *batch )
36 {
37 assert(batch->map == NULL);
38
39 batch->offset = (unsigned long)batch->ptr;
40 batch->offset = (batch->offset + 63) & ~63;
41 batch->ptr = (unsigned char *) batch->offset;
42
43 if (BATCH_SZ - batch->offset < BATCH_REFILL) {
44 bmBufferData(batch->intel,
45 batch->buffer,
46 BATCH_SZ,
47 NULL,
48 0);
49 batch->offset = 0;
50 batch->ptr = NULL;
51 }
52
53 batch->flags = 0;
54 }
55
56 static void intel_batchbuffer_reset_cb( struct intel_context *intel,
57 void *ptr )
58 {
59 struct intel_batchbuffer *batch = (struct intel_batchbuffer *)ptr;
60 assert(batch->map == NULL);
61 batch->flags = 0;
62 batch->offset = 0;
63 batch->ptr = NULL;
64 }
65
66 GLubyte *intel_batchbuffer_map( struct intel_batchbuffer *batch )
67 {
68 if (!batch->map) {
69 batch->map = bmMapBuffer(batch->intel, batch->buffer,
70 BM_MEM_AGP|BM_MEM_LOCAL|BM_CLIENT|BM_WRITE);
71 batch->ptr += (unsigned long)batch->map;
72 }
73
74 return batch->map;
75 }
76
77 void intel_batchbuffer_unmap( struct intel_batchbuffer *batch )
78 {
79 if (batch->map) {
80 batch->ptr -= (unsigned long)batch->map;
81 batch->map = NULL;
82 bmUnmapBuffer(batch->intel, batch->buffer);
83 }
84 }
85
86
87
88 /*======================================================================
89 * Public functions
90 */
91 struct intel_batchbuffer *intel_batchbuffer_alloc( struct intel_context *intel )
92 {
93 struct intel_batchbuffer *batch = calloc(sizeof(*batch), 1);
94
95 batch->intel = intel;
96
97 bmGenBuffers(intel, "batch", 1, &batch->buffer, 12);
98
99 bmBufferSetInvalidateCB(intel, batch->buffer,
100 intel_batchbuffer_reset_cb,
101 batch,
102 GL_TRUE);
103
104 bmBufferData(batch->intel,
105 batch->buffer,
106 BATCH_SZ,
107 NULL,
108 0);
109
110
111 return batch;
112 }
113
114 void intel_batchbuffer_free( struct intel_batchbuffer *batch )
115 {
116 if (batch->map)
117 bmUnmapBuffer(batch->intel, batch->buffer);
118
119 bmDeleteBuffers(batch->intel, 1, &batch->buffer);
120 free(batch);
121 }
122
123
124 #define MI_BATCH_BUFFER_END (0xA<<23)
125
126
127 GLboolean intel_batchbuffer_flush( struct intel_batchbuffer *batch )
128 {
129 struct intel_context *intel = batch->intel;
130 GLuint used = batch->ptr - (batch->map + batch->offset);
131 GLuint offset;
132 GLint retval = GL_TRUE;
133
134 assert(intel->locked);
135
136 if (used == 0) {
137 bmReleaseBuffers( batch->intel );
138 return GL_TRUE;
139 }
140
141 /* Add the MI_BATCH_BUFFER_END. Always add an MI_FLUSH - this is a
142 * performance drain that we would like to avoid.
143 */
144 if (used & 4) {
145 ((int *)batch->ptr)[0] = MI_BATCH_BUFFER_END;
146 batch->ptr += 4;
147 used += 4;
148 }
149 else {
150 ((int *)batch->ptr)[0] = 0;
151 ((int *)batch->ptr)[1] = MI_BATCH_BUFFER_END;
152
153 batch->ptr += 8;
154 used += 8;
155 }
156
157 intel_batchbuffer_unmap(batch);
158
159 /* Get the batch buffer offset: Must call bmBufferOffset() before
160 * bmValidateBuffers(), otherwise the buffer won't be on the inuse
161 * list.
162 */
163 offset = bmBufferOffset(batch->intel, batch->buffer);
164
165 if (bmValidateBuffers( batch->intel ) != 0) {
166 assert(intel->locked);
167 bmReleaseBuffers( batch->intel );
168 retval = GL_FALSE;
169 goto out;
170 }
171
172 if (INTEL_DEBUG & DEBUG_BATCH) {
173 char *map;
174
175 map = bmMapBuffer(batch->intel, batch->buffer,
176 BM_MEM_AGP|BM_MEM_LOCAL|BM_CLIENT);
177 intel_decode((uint32_t *)(map + batch->offset), used / 4,
178 offset + batch->offset, intel->intelScreen->deviceID);
179 bmUnmapBuffer(batch->intel, batch->buffer);
180 }
181
182 /* Fire the batch buffer, which was uploaded above:
183 */
184 intel_batch_ioctl(batch->intel,
185 offset + batch->offset,
186 used);
187
188 /* Reset the buffer:
189 */
190 out:
191 intel_batchbuffer_reset( batch );
192 intel_batchbuffer_map( batch );
193
194 if (!retval)
195 DBG("%s failed\n", __FUNCTION__);
196
197 return retval;
198 }
199
200
201
202
203
204
205
206 void intel_batchbuffer_align( struct intel_batchbuffer *batch,
207 GLuint align,
208 GLuint sz )
209 {
210 unsigned long ptr = (unsigned long) batch->ptr;
211 unsigned long aptr = (ptr + align) & ~((unsigned long)align-1);
212 GLuint fixup = aptr - ptr;
213
214 if (intel_batchbuffer_space(batch) < fixup + sz)
215 intel_batchbuffer_flush(batch);
216 else {
217 memset(batch->ptr, 0, fixup);
218 batch->ptr += fixup;
219 }
220 }
221
222
223
224
225 void intel_batchbuffer_data(struct intel_batchbuffer *batch,
226 const void *data,
227 GLuint bytes,
228 GLuint flags)
229 {
230 assert((bytes & 3) == 0);
231 intel_batchbuffer_require_space(batch, bytes, flags);
232 __memcpy(batch->ptr, data, bytes);
233 batch->ptr += bytes;
234 }
235