1 /**************************************************************************
3 * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
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:
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
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.
26 **************************************************************************/
29 #include "cell_context.h"
30 #include "cell_batch.h"
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]
43 cell_get_empty_buffer(struct cell_context
*cell
)
45 uint buf
= 0, tries
= 0;
47 /* Find a buffer that's marked as free by all SPUs */
49 uint spu
, num_free
= 0;
51 for (spu
= 0; spu
< cell
->num_spus
; spu
++) {
52 if (cell
->buffer_status
[spu
][buf
][0] == CELL_BUFFER_STATUS_FREE
) {
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
;
61 printf("PPU: ALLOC BUFFER %u\n", buf);
72 buf
= (buf
+ 1) % CELL_NUM_BUFFERS
;
77 printf("PPU WAITING for buffer...\n");
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.
90 cell_batch_flush(struct cell_context
*cell
)
92 static boolean flushing
= FALSE
;
93 uint batch
= cell
->cur_batch
;
94 const uint size
= cell
->buffer_size
[batch
];
104 assert(batch
< CELL_NUM_BUFFERS
);
107 printf("cell_batch_dispatch: buf %u at %p, size %u\n",
108 batch, &cell->buffer[batch][0], size);
112 * Build "BATCH" command and send to all SPUs.
114 cmd_word
= CELL_CMD_BATCH
| (batch
<< 8) | (size
<< 16);
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
);
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.
126 batch
= cell_get_empty_buffer(cell
);
128 cell
->buffer_size
[batch
] = 0; /* empty */
129 cell
->cur_batch
= batch
;
136 * Return the number of bytes free in the current batch buffer.
139 cell_batch_free_space(const struct cell_context
*cell
)
141 uint free
= CELL_BUFFER_SIZE
- cell
->buffer_size
[cell
->cur_batch
];
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
152 cell_batch_append(struct cell_context
*cell
, const void *data
, uint bytes
)
156 ASSERT(bytes
% 8 == 0);
157 ASSERT(bytes
<= CELL_BUFFER_SIZE
);
158 ASSERT(cell
->cur_batch
>= 0);
163 for (spu
= 0; spu
< cell
->num_spus
; spu
++) {
164 ASSERT(cell
->buffer_status
[spu
][cell
->cur_batch
][0]
165 == CELL_BUFFER_STATUS_USED
);
170 size
= cell
->buffer_size
[cell
->cur_batch
];
172 if (size
+ bytes
> CELL_BUFFER_SIZE
) {
173 cell_batch_flush(cell
);
177 ASSERT(size
+ bytes
<= CELL_BUFFER_SIZE
);
179 memcpy(cell
->buffer
[cell
->cur_batch
] + size
, data
, bytes
);
181 cell
->buffer_size
[cell
->cur_batch
] = size
+ bytes
;
186 * Allocate space in the current batch buffer for 'bytes' space.
187 * \return address in batch buffer to put data
190 cell_batch_alloc(struct cell_context
*cell
, uint bytes
)
192 return cell_batch_alloc_aligned(cell
, bytes
, 1);
197 * Same as \sa cell_batch_alloc, but return an address at a particular
201 cell_batch_alloc_aligned(struct cell_context
*cell
, uint bytes
,
207 ASSERT(bytes
% 8 == 0);
208 ASSERT(bytes
<= CELL_BUFFER_SIZE
);
209 ASSERT(alignment
> 0);
210 ASSERT(cell
->cur_batch
>= 0);
215 for (spu
= 0; spu
< cell
->num_spus
; spu
++) {
216 ASSERT(cell
->buffer_status
[spu
][cell
->cur_batch
][0]
217 == CELL_BUFFER_STATUS_USED
);
222 size
= cell
->buffer_size
[cell
->cur_batch
];
224 padbytes
= (alignment
- (size
% alignment
)) % alignment
;
226 if (padbytes
+ size
+ bytes
> CELL_BUFFER_SIZE
) {
227 cell_batch_flush(cell
);
234 ASSERT(size
% alignment
== 0);
235 ASSERT(size
+ bytes
<= CELL_BUFFER_SIZE
);
237 pos
= (void *) (cell
->buffer
[cell
->cur_batch
] + size
);
239 cell
->buffer_size
[cell
->cur_batch
] = size
+ bytes
;
246 * One-time init of batch buffers.
249 cell_init_batch_buffers(struct cell_context
*cell
)
253 /* init command, vertex/index buffer info */
254 for (buf
= 0; buf
< CELL_NUM_BUFFERS
; buf
++) {
255 cell
->buffer_size
[buf
] = 0;
257 /* init batch buffer status values,
258 * mark 0th buffer as used, rest as free.
260 for (spu
= 0; spu
< cell
->num_spus
; spu
++) {
262 cell
->buffer_status
[spu
][buf
][0] = CELL_BUFFER_STATUS_USED
;
264 cell
->buffer_status
[spu
][buf
][0] = CELL_BUFFER_STATUS_FREE
;