Merge remote branch 'origin/master' into pipe-video
[mesa.git] / src / gallium / drivers / r300 / r300_screen_buffer.c
1 /*
2 * Copyright 2010 Red Hat Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * on the rights to use, copy, modify, merge, publish, distribute, sub
8 * license, and/or sell copies of the Software, and to permit persons to whom
9 * the Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21 * USE OR OTHER DEALINGS IN THE SOFTWARE.
22 *
23 * Authors: Dave Airlie
24 */
25
26 #include <stdio.h>
27
28 #include "util/u_inlines.h"
29 #include "util/u_memory.h"
30 #include "util/u_upload_mgr.h"
31 #include "util/u_math.h"
32
33 #include "r300_screen_buffer.h"
34 #include "r300_winsys.h"
35
36 unsigned r300_buffer_is_referenced(struct pipe_context *context,
37 struct pipe_resource *buf,
38 enum r300_reference_domain domain)
39 {
40 struct r300_context *r300 = r300_context(context);
41 struct r300_buffer *rbuf = r300_buffer(buf);
42
43 if (r300_buffer_is_user_buffer(buf))
44 return PIPE_UNREFERENCED;
45
46 if (r300->rws->cs_is_buffer_referenced(r300->cs, rbuf->cs_buf, domain))
47 return PIPE_REFERENCED_FOR_READ | PIPE_REFERENCED_FOR_WRITE;
48
49 return PIPE_UNREFERENCED;
50 }
51
52 static unsigned r300_buffer_is_referenced_by_cs(struct pipe_context *context,
53 struct pipe_resource *buf,
54 unsigned level, int layer)
55 {
56 return r300_buffer_is_referenced(context, buf, R300_REF_CS);
57 }
58
59 /* External helper, not required to implent u_resource_vtbl:
60 */
61 int r300_upload_index_buffer(struct r300_context *r300,
62 struct pipe_resource **index_buffer,
63 unsigned index_size,
64 unsigned start,
65 unsigned count,
66 unsigned *out_offset)
67 {
68 struct pipe_resource *upload_buffer = NULL;
69 unsigned index_offset = start * index_size;
70 int ret = 0;
71
72 if (r300_buffer_is_user_buffer(*index_buffer)) {
73 ret = u_upload_buffer(r300->upload_ib,
74 index_offset,
75 count * index_size,
76 *index_buffer,
77 &index_offset,
78 &upload_buffer);
79 if (ret) {
80 goto done;
81 }
82 *index_buffer = upload_buffer;
83 *out_offset = index_offset / index_size;
84 } else
85 *out_offset = start;
86
87 done:
88 // if (upload_buffer)
89 // pipe_resource_reference(&upload_buffer, NULL);
90 return ret;
91 }
92
93 /* External helper, not required to implement u_resource_vtbl:
94 */
95 int r300_upload_user_buffers(struct r300_context *r300)
96 {
97 enum pipe_error ret = PIPE_OK;
98 int i, nr;
99
100 nr = r300->velems->count;
101
102 for (i = 0; i < nr; i++) {
103 struct pipe_vertex_buffer *vb =
104 &r300->vertex_buffer[r300->velems->velem[i].vertex_buffer_index];
105
106 if (r300_buffer_is_user_buffer(vb->buffer)) {
107 struct pipe_resource *upload_buffer = NULL;
108 unsigned offset = 0; /*vb->buffer_offset * 4;*/
109 unsigned size = vb->buffer->width0;
110 unsigned upload_offset;
111 ret = u_upload_buffer(r300->upload_vb,
112 offset, size,
113 vb->buffer,
114 &upload_offset, &upload_buffer);
115 if (ret)
116 return ret;
117
118 pipe_resource_reference(&vb->buffer, NULL);
119 vb->buffer = upload_buffer;
120 vb->buffer_offset = upload_offset;
121 r300->validate_buffers = TRUE;
122 }
123 }
124 return ret;
125 }
126
127 static void r300_buffer_destroy(struct pipe_screen *screen,
128 struct pipe_resource *buf)
129 {
130 struct r300_screen *r300screen = r300_screen(screen);
131 struct r300_buffer *rbuf = r300_buffer(buf);
132 struct r300_winsys_screen *rws = r300screen->rws;
133
134 if (rbuf->constant_buffer)
135 FREE(rbuf->constant_buffer);
136
137 if (rbuf->buf)
138 rws->buffer_reference(rws, &rbuf->buf, NULL);
139
140 util_slab_free(&r300screen->pool_buffers, rbuf);
141 }
142
143 static struct pipe_transfer*
144 r300_buffer_get_transfer(struct pipe_context *context,
145 struct pipe_resource *resource,
146 unsigned level,
147 unsigned usage,
148 const struct pipe_box *box)
149 {
150 struct r300_context *r300 = r300_context(context);
151 struct pipe_transfer *transfer =
152 util_slab_alloc(&r300->pool_transfers);
153
154 transfer->resource = resource;
155 transfer->level = level;
156 transfer->usage = usage;
157 transfer->box = *box;
158 transfer->stride = 0;
159 transfer->layer_stride = 0;
160 transfer->data = NULL;
161
162 /* Note strides are zero, this is ok for buffers, but not for
163 * textures 2d & higher at least.
164 */
165 return transfer;
166 }
167
168 static void r300_buffer_transfer_destroy(struct pipe_context *pipe,
169 struct pipe_transfer *transfer)
170 {
171 struct r300_context *r300 = r300_context(pipe);
172 util_slab_free(&r300->pool_transfers, transfer);
173 }
174
175 static void *
176 r300_buffer_transfer_map( struct pipe_context *pipe,
177 struct pipe_transfer *transfer )
178 {
179 struct r300_context *r300 = r300_context(pipe);
180 struct r300_screen *r300screen = r300_screen(pipe->screen);
181 struct r300_winsys_screen *rws = r300screen->rws;
182 struct r300_buffer *rbuf = r300_buffer(transfer->resource);
183 uint8_t *map;
184 boolean flush = FALSE;
185 unsigned i;
186
187 if (rbuf->user_buffer)
188 return (uint8_t *) rbuf->user_buffer + transfer->box.x;
189 if (rbuf->constant_buffer)
190 return (uint8_t *) rbuf->constant_buffer + transfer->box.x;
191
192 /* check if the mapping is to a range we already flushed */
193 if (transfer->usage & PIPE_TRANSFER_DISCARD) {
194 for (i = 0; i < rbuf->num_ranges; i++) {
195 if ((transfer->box.x >= rbuf->ranges[i].start) &&
196 (transfer->box.x < rbuf->ranges[i].end))
197 flush = TRUE;
198
199 if (flush) {
200 /* unreference this hw buffer and allocate a new one */
201 rws->buffer_reference(rws, &rbuf->buf, NULL);
202
203 rbuf->num_ranges = 0;
204 rbuf->buf =
205 r300screen->rws->buffer_create(r300screen->rws,
206 rbuf->b.b.width0, 16,
207 rbuf->b.b.bind,
208 rbuf->b.b.usage,
209 rbuf->domain);
210 rbuf->cs_buf =
211 r300screen->rws->buffer_get_cs_handle(r300screen->rws,
212 rbuf->buf);
213 break;
214 }
215 }
216 }
217
218 map = rws->buffer_map(rws, rbuf->buf, r300->cs, transfer->usage);
219
220 if (map == NULL)
221 return NULL;
222
223 /* map_buffer() returned a pointer to the beginning of the buffer,
224 * but transfers are expected to return a pointer to just the
225 * region specified in the box.
226 */
227 return map + transfer->box.x;
228 }
229
230 static void r300_buffer_transfer_flush_region( struct pipe_context *pipe,
231 struct pipe_transfer *transfer,
232 const struct pipe_box *box)
233 {
234 struct r300_buffer *rbuf = r300_buffer(transfer->resource);
235 unsigned i;
236 unsigned offset = transfer->box.x + box->x;
237 unsigned length = box->width;
238
239 assert(box->x + box->width <= transfer->box.width);
240
241 if (rbuf->user_buffer)
242 return;
243 if (rbuf->constant_buffer)
244 return;
245
246 /* mark the range as used */
247 for(i = 0; i < rbuf->num_ranges; ++i) {
248 if(offset <= rbuf->ranges[i].end && rbuf->ranges[i].start <= (offset+box->width)) {
249 rbuf->ranges[i].start = MIN2(rbuf->ranges[i].start, offset);
250 rbuf->ranges[i].end = MAX2(rbuf->ranges[i].end, (offset+length));
251 return;
252 }
253 }
254
255 rbuf->ranges[rbuf->num_ranges].start = offset;
256 rbuf->ranges[rbuf->num_ranges].end = offset+length;
257 rbuf->num_ranges++;
258 }
259
260 static void r300_buffer_transfer_unmap( struct pipe_context *pipe,
261 struct pipe_transfer *transfer )
262 {
263 struct r300_screen *r300screen = r300_screen(pipe->screen);
264 struct r300_winsys_screen *rws = r300screen->rws;
265 struct r300_buffer *rbuf = r300_buffer(transfer->resource);
266
267 if (rbuf->buf) {
268 rws->buffer_unmap(rws, rbuf->buf);
269 }
270 }
271
272 static void r300_buffer_transfer_inline_write(struct pipe_context *pipe,
273 struct pipe_resource *resource,
274 unsigned level,
275 unsigned usage,
276 const struct pipe_box *box,
277 const void *data,
278 unsigned stride,
279 unsigned layer_stride)
280 {
281 struct r300_buffer *rbuf = r300_buffer(resource);
282 struct pipe_transfer *transfer = NULL;
283 uint8_t *map = NULL;
284
285 if (rbuf->constant_buffer) {
286 memcpy(rbuf->constant_buffer + box->x, data, box->width);
287 return;
288 }
289
290 transfer = r300_buffer_get_transfer(pipe, resource, 0,
291 PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD, box);
292 map = r300_buffer_transfer_map(pipe, transfer);
293
294 memcpy(map, data, box->width);
295
296 r300_buffer_transfer_unmap(pipe, transfer);
297 r300_buffer_transfer_destroy(pipe, transfer);
298 }
299
300 struct u_resource_vtbl r300_buffer_vtbl =
301 {
302 u_default_resource_get_handle, /* get_handle */
303 r300_buffer_destroy, /* resource_destroy */
304 r300_buffer_is_referenced_by_cs, /* is_buffer_referenced */
305 r300_buffer_get_transfer, /* get_transfer */
306 r300_buffer_transfer_destroy, /* transfer_destroy */
307 r300_buffer_transfer_map, /* transfer_map */
308 r300_buffer_transfer_flush_region, /* transfer_flush_region */
309 r300_buffer_transfer_unmap, /* transfer_unmap */
310 r300_buffer_transfer_inline_write /* transfer_inline_write */
311 };
312
313 struct pipe_resource *r300_buffer_create(struct pipe_screen *screen,
314 const struct pipe_resource *templ)
315 {
316 struct r300_screen *r300screen = r300_screen(screen);
317 struct r300_buffer *rbuf;
318 unsigned alignment = 16;
319
320 rbuf = util_slab_alloc(&r300screen->pool_buffers);
321
322 rbuf->magic = R300_BUFFER_MAGIC;
323
324 rbuf->b.b = *templ;
325 rbuf->b.vtbl = &r300_buffer_vtbl;
326 pipe_reference_init(&rbuf->b.b.reference, 1);
327 rbuf->b.b.screen = screen;
328 rbuf->domain = R300_DOMAIN_GTT;
329 rbuf->num_ranges = 0;
330 rbuf->buf = NULL;
331 rbuf->constant_buffer = NULL;
332 rbuf->user_buffer = NULL;
333
334 /* Alloc constant buffers in RAM. */
335 if (templ->bind & PIPE_BIND_CONSTANT_BUFFER) {
336 rbuf->constant_buffer = MALLOC(templ->width0);
337 return &rbuf->b.b;
338 }
339
340 rbuf->buf =
341 r300screen->rws->buffer_create(r300screen->rws,
342 rbuf->b.b.width0, alignment,
343 rbuf->b.b.bind, rbuf->b.b.usage,
344 rbuf->domain);
345 rbuf->cs_buf =
346 r300screen->rws->buffer_get_cs_handle(r300screen->rws, rbuf->buf);
347
348 if (!rbuf->buf) {
349 util_slab_free(&r300screen->pool_buffers, rbuf);
350 return NULL;
351 }
352
353 return &rbuf->b.b;
354 }
355
356 struct pipe_resource *r300_user_buffer_create(struct pipe_screen *screen,
357 void *ptr,
358 unsigned bytes,
359 unsigned bind)
360 {
361 struct r300_screen *r300screen = r300_screen(screen);
362 struct r300_buffer *rbuf;
363
364 rbuf = util_slab_alloc(&r300screen->pool_buffers);
365
366 rbuf->magic = R300_BUFFER_MAGIC;
367
368 pipe_reference_init(&rbuf->b.b.reference, 1);
369 rbuf->b.vtbl = &r300_buffer_vtbl;
370 rbuf->b.b.screen = screen;
371 rbuf->b.b.target = PIPE_BUFFER;
372 rbuf->b.b.format = PIPE_FORMAT_R8_UNORM;
373 rbuf->b.b.usage = PIPE_USAGE_IMMUTABLE;
374 rbuf->b.b.bind = bind;
375 rbuf->b.b.width0 = bytes;
376 rbuf->b.b.height0 = 1;
377 rbuf->b.b.depth0 = 1;
378 rbuf->b.b.array_size = 1;
379 rbuf->b.b.flags = 0;
380 rbuf->domain = R300_DOMAIN_GTT;
381 rbuf->num_ranges = 0;
382 rbuf->buf = NULL;
383 rbuf->constant_buffer = NULL;
384 rbuf->user_buffer = ptr;
385 return &rbuf->b.b;
386 }