winsys/sw: Add a software winsys layered on a pipe
[mesa/mesa-lb.git] / src / gallium / drivers / cell / ppu / cell_batch.c
blobfe144f8b84954f1540a0f3336b2a0f685d285566
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:
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.
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"
31 #include "cell_fence.h"
32 #include "cell_spu.h"
36 /**
37 * Search the buffer pool for an empty/free buffer and return its index.
38 * Buffers are used for storing vertex data, state and commands which
39 * will be sent to the SPUs.
40 * If no empty buffers are available, wait for one.
41 * \return buffer index in [0, CELL_NUM_BUFFERS-1]
43 uint
44 cell_get_empty_buffer(struct cell_context *cell)
46 static uint prev_buffer = 0;
47 uint buf = (prev_buffer + 1) % CELL_NUM_BUFFERS;
48 uint tries = 0;
50 /* Find a buffer that's marked as free by all SPUs */
51 while (1) {
52 uint spu, num_free = 0;
54 for (spu = 0; spu < cell->num_spus; spu++) {
55 if (cell->buffer_status[spu][buf][0] == CELL_BUFFER_STATUS_FREE) {
56 num_free++;
58 if (num_free == cell->num_spus) {
59 /* found a free buffer, now mark status as used */
60 for (spu = 0; spu < cell->num_spus; spu++) {
61 cell->buffer_status[spu][buf][0] = CELL_BUFFER_STATUS_USED;
64 printf("PPU: ALLOC BUFFER %u, %u tries\n", buf, tries);
66 prev_buffer = buf;
68 /* release tex buffer associated w/ prev use of this batch buf */
69 cell_free_fenced_buffers(cell, &cell->fenced_buffers[buf]);
71 return buf;
74 else {
75 break;
79 /* try next buf */
80 buf = (buf + 1) % CELL_NUM_BUFFERS;
82 tries++;
83 if (tries == 100) {
85 printf("PPU WAITING for buffer...\n");
92 /**
93 * Append a fence command to the current batch buffer.
94 * Note that we're sure there's always room for this because of the
95 * adjusted size check in cell_batch_free_space().
97 static void
98 emit_fence(struct cell_context *cell)
100 const uint batch = cell->cur_batch;
101 const uint size = cell->buffer_size[batch];
102 struct cell_command_fence *fence_cmd;
103 struct cell_fence *fence = &cell->fenced_buffers[batch].fence;
104 uint i;
106 /* set fence status to emitted, not yet signalled */
107 for (i = 0; i < cell->num_spus; i++) {
108 fence->status[i][0] = CELL_FENCE_EMITTED;
111 STATIC_ASSERT(sizeof(struct cell_command_fence) % 16 == 0);
112 ASSERT(size % 16 == 0);
113 ASSERT(size + sizeof(struct cell_command_fence) <= CELL_BUFFER_SIZE);
115 fence_cmd = (struct cell_command_fence *) (cell->buffer[batch] + size);
116 fence_cmd->opcode[0] = CELL_CMD_FENCE;
117 fence_cmd->fence = fence;
119 /* update batch buffer size */
120 cell->buffer_size[batch] = size + sizeof(struct cell_command_fence);
125 * Flush the current batch buffer to the SPUs.
126 * An empty buffer will be found and set as the new current batch buffer
127 * for subsequent commands/data.
129 void
130 cell_batch_flush(struct cell_context *cell)
132 static boolean flushing = FALSE;
133 uint batch = cell->cur_batch;
134 uint size = cell->buffer_size[batch];
135 uint spu, cmd_word;
137 assert(!flushing);
139 if (size == 0)
140 return;
142 /* Before we use this batch buffer, make sure any fenced texture buffers
143 * are released.
145 if (cell->fenced_buffers[batch].head) {
146 emit_fence(cell);
147 size = cell->buffer_size[batch];
150 flushing = TRUE;
152 assert(batch < CELL_NUM_BUFFERS);
155 printf("cell_batch_dispatch: buf %u at %p, size %u\n",
156 batch, &cell->buffer[batch][0], size);
160 * Build "BATCH" command and send to all SPUs.
162 cmd_word = CELL_CMD_BATCH | (batch << 8) | (size << 16);
164 for (spu = 0; spu < cell->num_spus; spu++) {
165 assert(cell->buffer_status[spu][batch][0] == CELL_BUFFER_STATUS_USED);
166 send_mbox_message(cell_global.spe_contexts[spu], cmd_word);
169 /* When the SPUs are done copying the buffer into their locals stores
170 * they'll write a BUFFER_STATUS_FREE message into the buffer_status[]
171 * array indicating that the PPU can re-use the buffer.
174 batch = cell_get_empty_buffer(cell);
176 cell->buffer_size[batch] = 0; /* empty */
177 cell->cur_batch = batch;
179 flushing = FALSE;
184 * Return the number of bytes free in the current batch buffer.
186 uint
187 cell_batch_free_space(const struct cell_context *cell)
189 uint free = CELL_BUFFER_SIZE - cell->buffer_size[cell->cur_batch];
190 free -= sizeof(struct cell_command_fence);
191 return free;
196 * Allocate space in the current batch buffer for 'bytes' space.
197 * Bytes must be a multiple of 16 bytes. Allocation will be 16 byte aligned.
198 * \return address in batch buffer to put data
200 void *
201 cell_batch_alloc16(struct cell_context *cell, uint bytes)
203 void *pos;
204 uint size;
206 ASSERT(bytes % 16 == 0);
207 ASSERT(bytes <= CELL_BUFFER_SIZE);
208 ASSERT(cell->cur_batch >= 0);
210 #ifdef ASSERT
212 uint spu;
213 for (spu = 0; spu < cell->num_spus; spu++) {
214 ASSERT(cell->buffer_status[spu][cell->cur_batch][0]
215 == CELL_BUFFER_STATUS_USED);
218 #endif
220 size = cell->buffer_size[cell->cur_batch];
222 if (bytes > cell_batch_free_space(cell)) {
223 cell_batch_flush(cell);
224 size = 0;
227 ASSERT(size % 16 == 0);
228 ASSERT(size + bytes <= CELL_BUFFER_SIZE);
230 pos = (void *) (cell->buffer[cell->cur_batch] + size);
232 cell->buffer_size[cell->cur_batch] = size + bytes;
234 return pos;
239 * One-time init of batch buffers.
241 void
242 cell_init_batch_buffers(struct cell_context *cell)
244 uint spu, buf;
246 /* init command, vertex/index buffer info */
247 for (buf = 0; buf < CELL_NUM_BUFFERS; buf++) {
248 cell->buffer_size[buf] = 0;
250 /* init batch buffer status values,
251 * mark 0th buffer as used, rest as free.
253 for (spu = 0; spu < cell->num_spus; spu++) {
254 if (buf == 0)
255 cell->buffer_status[spu][buf][0] = CELL_BUFFER_STATUS_USED;
256 else
257 cell->buffer_status[spu][buf][0] = CELL_BUFFER_STATUS_FREE;