Merge branch 'master' into gallium-0.2
[mesa.git] / src / gallium / drivers / cell / ppu / cell_batch.c
1 /**************************************************************************
2 *
3 * Copyright 2007 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
29 #include "cell_context.h"
30 #include "cell_batch.h"
31 #include "cell_spu.h"
32
33
34
35 /**
36 * Search the buffer pool for an empty/free buffer and return its index.
37 * Buffers are used for storing vertex data, state and commands which
38 * will be sent to the SPUs.
39 * If no empty buffers are available, wait for one.
40 * \return buffer index in [0, CELL_NUM_BUFFERS-1]
41 */
42 uint
43 cell_get_empty_buffer(struct cell_context *cell)
44 {
45 uint buf = 0, tries = 0;
46
47 /* Find a buffer that's marked as free by all SPUs */
48 while (1) {
49 uint spu, num_free = 0;
50
51 for (spu = 0; spu < cell->num_spus; spu++) {
52 if (cell->buffer_status[spu][buf][0] == CELL_BUFFER_STATUS_FREE) {
53 num_free++;
54
55 if (num_free == cell->num_spus) {
56 /* found a free buffer, now mark status as used */
57 for (spu = 0; spu < cell->num_spus; spu++) {
58 cell->buffer_status[spu][buf][0] = CELL_BUFFER_STATUS_USED;
59 }
60 /*
61 printf("PPU: ALLOC BUFFER %u\n", buf);
62 */
63 return buf;
64 }
65 }
66 else {
67 break;
68 }
69 }
70
71 /* try next buf */
72 buf = (buf + 1) % CELL_NUM_BUFFERS;
73
74 tries++;
75 if (tries == 100) {
76 /*
77 printf("PPU WAITING for buffer...\n");
78 */
79 }
80 }
81 }
82
83
84 /**
85 * Flush the current batch buffer to the SPUs.
86 * An empty buffer will be found and set as the new current batch buffer
87 * for subsequent commands/data.
88 */
89 void
90 cell_batch_flush(struct cell_context *cell)
91 {
92 static boolean flushing = FALSE;
93 uint batch = cell->cur_batch;
94 const uint size = cell->buffer_size[batch];
95 uint spu, cmd_word;
96
97 assert(!flushing);
98
99 if (size == 0)
100 return;
101
102 flushing = TRUE;
103
104 assert(batch < CELL_NUM_BUFFERS);
105
106 /*
107 printf("cell_batch_dispatch: buf %u at %p, size %u\n",
108 batch, &cell->buffer[batch][0], size);
109 */
110
111 /*
112 * Build "BATCH" command and send to all SPUs.
113 */
114 cmd_word = CELL_CMD_BATCH | (batch << 8) | (size << 16);
115
116 for (spu = 0; spu < cell->num_spus; spu++) {
117 assert(cell->buffer_status[spu][batch][0] == CELL_BUFFER_STATUS_USED);
118 send_mbox_message(cell_global.spe_contexts[spu], cmd_word);
119 }
120
121 /* When the SPUs are done copying the buffer into their locals stores
122 * they'll write a BUFFER_STATUS_FREE message into the buffer_status[]
123 * array indicating that the PPU can re-use the buffer.
124 */
125
126 batch = cell_get_empty_buffer(cell);
127
128 cell->buffer_size[batch] = 0; /* empty */
129 cell->cur_batch = batch;
130
131 flushing = FALSE;
132 }
133
134
135 /**
136 * Return the number of bytes free in the current batch buffer.
137 */
138 uint
139 cell_batch_free_space(const struct cell_context *cell)
140 {
141 uint free = CELL_BUFFER_SIZE - cell->buffer_size[cell->cur_batch];
142 return free;
143 }
144
145
146 /**
147 * Append data to the current batch buffer.
148 * \param data address of block of bytes to append
149 * \param bytes size of block of bytes
150 */
151 void
152 cell_batch_append(struct cell_context *cell, const void *data, uint bytes)
153 {
154 uint size;
155
156 ASSERT(bytes % 8 == 0);
157 ASSERT(bytes <= CELL_BUFFER_SIZE);
158 ASSERT(cell->cur_batch >= 0);
159
160 #ifdef ASSERT
161 {
162 uint spu;
163 for (spu = 0; spu < cell->num_spus; spu++) {
164 ASSERT(cell->buffer_status[spu][cell->cur_batch][0]
165 == CELL_BUFFER_STATUS_USED);
166 }
167 }
168 #endif
169
170 size = cell->buffer_size[cell->cur_batch];
171
172 if (size + bytes > CELL_BUFFER_SIZE) {
173 cell_batch_flush(cell);
174 size = 0;
175 }
176
177 ASSERT(size + bytes <= CELL_BUFFER_SIZE);
178
179 memcpy(cell->buffer[cell->cur_batch] + size, data, bytes);
180
181 cell->buffer_size[cell->cur_batch] = size + bytes;
182 }
183
184
185 /**
186 * Allocate space in the current batch buffer for 'bytes' space.
187 * \return address in batch buffer to put data
188 */
189 void *
190 cell_batch_alloc(struct cell_context *cell, uint bytes)
191 {
192 return cell_batch_alloc_aligned(cell, bytes, 1);
193 }
194
195
196 /**
197 * Same as \sa cell_batch_alloc, but return an address at a particular
198 * alignment.
199 */
200 void *
201 cell_batch_alloc_aligned(struct cell_context *cell, uint bytes,
202 uint alignment)
203 {
204 void *pos;
205 uint size, padbytes;
206
207 ASSERT(bytes % 8 == 0);
208 ASSERT(bytes <= CELL_BUFFER_SIZE);
209 ASSERT(alignment > 0);
210 ASSERT(cell->cur_batch >= 0);
211
212 #ifdef ASSERT
213 {
214 uint spu;
215 for (spu = 0; spu < cell->num_spus; spu++) {
216 ASSERT(cell->buffer_status[spu][cell->cur_batch][0]
217 == CELL_BUFFER_STATUS_USED);
218 }
219 }
220 #endif
221
222 size = cell->buffer_size[cell->cur_batch];
223
224 padbytes = (alignment - (size % alignment)) % alignment;
225
226 if (padbytes + size + bytes > CELL_BUFFER_SIZE) {
227 cell_batch_flush(cell);
228 size = 0;
229 }
230 else {
231 size += padbytes;
232 }
233
234 ASSERT(size % alignment == 0);
235 ASSERT(size + bytes <= CELL_BUFFER_SIZE);
236
237 pos = (void *) (cell->buffer[cell->cur_batch] + size);
238
239 cell->buffer_size[cell->cur_batch] = size + bytes;
240
241 return pos;
242 }
243
244
245 /**
246 * One-time init of batch buffers.
247 */
248 void
249 cell_init_batch_buffers(struct cell_context *cell)
250 {
251 uint spu, buf;
252
253 /* init command, vertex/index buffer info */
254 for (buf = 0; buf < CELL_NUM_BUFFERS; buf++) {
255 cell->buffer_size[buf] = 0;
256
257 /* init batch buffer status values,
258 * mark 0th buffer as used, rest as free.
259 */
260 for (spu = 0; spu < cell->num_spus; spu++) {
261 if (buf == 0)
262 cell->buffer_status[spu][buf][0] = CELL_BUFFER_STATUS_USED;
263 else
264 cell->buffer_status[spu][buf][0] = CELL_BUFFER_STATUS_FREE;
265 }
266 }
267 }