softpipe: handle vertex texture sampling when using llvm for draw
[mesa.git] / src / gallium / drivers / softpipe / sp_texture.c
1 /**************************************************************************
2 *
3 * Copyright 2006 VMware, Inc.
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 VMWARE 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 * Authors:
29 * Keith Whitwell <keithw@vmware.com>
30 * Michel Dänzer <daenzer@vmware.com>
31 */
32
33 #include "pipe/p_defines.h"
34 #include "util/u_inlines.h"
35
36 #include "util/u_format.h"
37 #include "util/u_math.h"
38 #include "util/u_memory.h"
39 #include "util/u_transfer.h"
40
41 #include "sp_context.h"
42 #include "sp_flush.h"
43 #include "sp_texture.h"
44 #include "sp_screen.h"
45
46 #include "state_tracker/sw_winsys.h"
47
48
49 /**
50 * Conventional allocation path for non-display textures:
51 * Use a simple, maximally packed layout.
52 */
53 static boolean
54 softpipe_resource_layout(struct pipe_screen *screen,
55 struct softpipe_resource *spr,
56 boolean allocate)
57 {
58 struct pipe_resource *pt = &spr->base;
59 unsigned level;
60 unsigned width = pt->width0;
61 unsigned height = pt->height0;
62 unsigned depth = pt->depth0;
63 uint64_t buffer_size = 0;
64
65 for (level = 0; level <= pt->last_level; level++) {
66 unsigned slices, nblocksy;
67
68 nblocksy = util_format_get_nblocksy(pt->format, height);
69
70 if (pt->target == PIPE_TEXTURE_CUBE)
71 slices = 6;
72 else if (pt->target == PIPE_TEXTURE_3D)
73 slices = depth;
74 else
75 slices = pt->array_size;
76
77 spr->stride[level] = util_format_get_stride(pt->format, width);
78
79 spr->level_offset[level] = buffer_size;
80
81 /* if row_stride * height > SP_MAX_TEXTURE_SIZE */
82 if ((uint64_t)spr->stride[level] * nblocksy > SP_MAX_TEXTURE_SIZE) {
83 /* image too large */
84 return FALSE;
85 }
86
87 spr->img_stride[level] = spr->stride[level] * nblocksy;
88
89 buffer_size += (uint64_t) spr->img_stride[level] * slices;
90
91 width = u_minify(width, 1);
92 height = u_minify(height, 1);
93 depth = u_minify(depth, 1);
94 }
95
96 if (buffer_size > SP_MAX_TEXTURE_SIZE)
97 return FALSE;
98
99 if (allocate) {
100 spr->data = align_malloc(buffer_size, 64);
101 return spr->data != NULL;
102 }
103 else {
104 return TRUE;
105 }
106 }
107
108
109 /**
110 * Check the size of the texture specified by 'res'.
111 * \return TRUE if OK, FALSE if too large.
112 */
113 static boolean
114 softpipe_can_create_resource(struct pipe_screen *screen,
115 const struct pipe_resource *res)
116 {
117 struct softpipe_resource spr;
118 memset(&spr, 0, sizeof(spr));
119 spr.base = *res;
120 return softpipe_resource_layout(screen, &spr, FALSE);
121 }
122
123
124 /**
125 * Texture layout for simple color buffers.
126 */
127 static boolean
128 softpipe_displaytarget_layout(struct pipe_screen *screen,
129 struct softpipe_resource *spr)
130 {
131 struct sw_winsys *winsys = softpipe_screen(screen)->winsys;
132
133 /* Round up the surface size to a multiple of the tile size?
134 */
135 spr->dt = winsys->displaytarget_create(winsys,
136 spr->base.bind,
137 spr->base.format,
138 spr->base.width0,
139 spr->base.height0,
140 64,
141 &spr->stride[0] );
142
143 return spr->dt != NULL;
144 }
145
146
147 /**
148 * Create new pipe_resource given the template information.
149 */
150 static struct pipe_resource *
151 softpipe_resource_create(struct pipe_screen *screen,
152 const struct pipe_resource *templat)
153 {
154 struct softpipe_resource *spr = CALLOC_STRUCT(softpipe_resource);
155 if (!spr)
156 return NULL;
157
158 assert(templat->format != PIPE_FORMAT_NONE);
159
160 spr->base = *templat;
161 pipe_reference_init(&spr->base.reference, 1);
162 spr->base.screen = screen;
163
164 spr->pot = (util_is_power_of_two(templat->width0) &&
165 util_is_power_of_two(templat->height0) &&
166 util_is_power_of_two(templat->depth0));
167
168 if (spr->base.bind & (PIPE_BIND_DISPLAY_TARGET |
169 PIPE_BIND_SCANOUT |
170 PIPE_BIND_SHARED)) {
171 if (!softpipe_displaytarget_layout(screen, spr))
172 goto fail;
173 }
174 else {
175 if (!softpipe_resource_layout(screen, spr, TRUE))
176 goto fail;
177 }
178
179 return &spr->base;
180
181 fail:
182 FREE(spr);
183 return NULL;
184 }
185
186
187 static void
188 softpipe_resource_destroy(struct pipe_screen *pscreen,
189 struct pipe_resource *pt)
190 {
191 struct softpipe_screen *screen = softpipe_screen(pscreen);
192 struct softpipe_resource *spr = softpipe_resource(pt);
193
194 if (spr->dt) {
195 /* display target */
196 struct sw_winsys *winsys = screen->winsys;
197 winsys->displaytarget_destroy(winsys, spr->dt);
198 }
199 else if (!spr->userBuffer) {
200 /* regular texture */
201 align_free(spr->data);
202 }
203
204 FREE(spr);
205 }
206
207
208 static struct pipe_resource *
209 softpipe_resource_from_handle(struct pipe_screen *screen,
210 const struct pipe_resource *templat,
211 struct winsys_handle *whandle)
212 {
213 struct sw_winsys *winsys = softpipe_screen(screen)->winsys;
214 struct softpipe_resource *spr = CALLOC_STRUCT(softpipe_resource);
215 if (!spr)
216 return NULL;
217
218 spr->base = *templat;
219 pipe_reference_init(&spr->base.reference, 1);
220 spr->base.screen = screen;
221
222 spr->pot = (util_is_power_of_two(templat->width0) &&
223 util_is_power_of_two(templat->height0) &&
224 util_is_power_of_two(templat->depth0));
225
226 spr->dt = winsys->displaytarget_from_handle(winsys,
227 templat,
228 whandle,
229 &spr->stride[0]);
230 if (!spr->dt)
231 goto fail;
232
233 return &spr->base;
234
235 fail:
236 FREE(spr);
237 return NULL;
238 }
239
240
241 static boolean
242 softpipe_resource_get_handle(struct pipe_screen *screen,
243 struct pipe_resource *pt,
244 struct winsys_handle *whandle)
245 {
246 struct sw_winsys *winsys = softpipe_screen(screen)->winsys;
247 struct softpipe_resource *spr = softpipe_resource(pt);
248
249 assert(spr->dt);
250 if (!spr->dt)
251 return FALSE;
252
253 return winsys->displaytarget_get_handle(winsys, spr->dt, whandle);
254 }
255
256
257 /**
258 * Helper function to compute offset (in bytes) for a particular
259 * texture level/face/slice from the start of the buffer.
260 */
261 static unsigned
262 sp_get_tex_image_offset(const struct softpipe_resource *spr,
263 unsigned level, unsigned layer)
264 {
265 unsigned offset = spr->level_offset[level];
266
267 offset += layer * spr->img_stride[level];
268
269 return offset;
270 }
271
272
273 /**
274 * Get a pipe_surface "view" into a texture resource.
275 */
276 static struct pipe_surface *
277 softpipe_create_surface(struct pipe_context *pipe,
278 struct pipe_resource *pt,
279 const struct pipe_surface *surf_tmpl)
280 {
281 struct pipe_surface *ps;
282
283 ps = CALLOC_STRUCT(pipe_surface);
284 if (ps) {
285 pipe_reference_init(&ps->reference, 1);
286 pipe_resource_reference(&ps->texture, pt);
287 ps->context = pipe;
288 ps->format = surf_tmpl->format;
289 if (pt->target != PIPE_BUFFER) {
290 assert(surf_tmpl->u.tex.level <= pt->last_level);
291 ps->width = u_minify(pt->width0, surf_tmpl->u.tex.level);
292 ps->height = u_minify(pt->height0, surf_tmpl->u.tex.level);
293 ps->u.tex.level = surf_tmpl->u.tex.level;
294 ps->u.tex.first_layer = surf_tmpl->u.tex.first_layer;
295 ps->u.tex.last_layer = surf_tmpl->u.tex.last_layer;
296 if (ps->u.tex.first_layer != ps->u.tex.last_layer) {
297 debug_printf("creating surface with multiple layers, rendering to first layer only\n");
298 }
299 }
300 else {
301 /* setting width as number of elements should get us correct renderbuffer width */
302 ps->width = surf_tmpl->u.buf.last_element - surf_tmpl->u.buf.first_element + 1;
303 ps->height = pt->height0;
304 ps->u.buf.first_element = surf_tmpl->u.buf.first_element;
305 ps->u.buf.last_element = surf_tmpl->u.buf.last_element;
306 assert(ps->u.buf.first_element <= ps->u.buf.last_element);
307 assert(ps->u.buf.last_element < ps->width);
308 }
309 }
310 return ps;
311 }
312
313
314 /**
315 * Free a pipe_surface which was created with softpipe_create_surface().
316 */
317 static void
318 softpipe_surface_destroy(struct pipe_context *pipe,
319 struct pipe_surface *surf)
320 {
321 /* Effectively do the texture_update work here - if texture images
322 * needed post-processing to put them into hardware layout, this is
323 * where it would happen. For softpipe, nothing to do.
324 */
325 assert(surf->texture);
326 pipe_resource_reference(&surf->texture, NULL);
327 FREE(surf);
328 }
329
330
331 /**
332 * Geta pipe_transfer object which is used for moving data in/out of
333 * a resource object.
334 * \param pipe rendering context
335 * \param resource the resource to transfer in/out of
336 * \param level which mipmap level
337 * \param usage bitmask of PIPE_TRANSFER_x flags
338 * \param box the 1D/2D/3D region of interest
339 */
340 static void *
341 softpipe_transfer_map(struct pipe_context *pipe,
342 struct pipe_resource *resource,
343 unsigned level,
344 unsigned usage,
345 const struct pipe_box *box,
346 struct pipe_transfer **transfer)
347 {
348 struct sw_winsys *winsys = softpipe_screen(pipe->screen)->winsys;
349 struct softpipe_resource *spr = softpipe_resource(resource);
350 struct softpipe_transfer *spt;
351 struct pipe_transfer *pt;
352 enum pipe_format format = resource->format;
353 uint8_t *map;
354
355 assert(resource);
356 assert(level <= resource->last_level);
357
358 /* make sure the requested region is in the image bounds */
359 assert(box->x + box->width <= (int) u_minify(resource->width0, level));
360 if (resource->target == PIPE_TEXTURE_1D_ARRAY) {
361 assert(box->y + box->height <= (int) resource->array_size);
362 }
363 else {
364 assert(box->y + box->height <= (int) u_minify(resource->height0, level));
365 if (resource->target == PIPE_TEXTURE_2D_ARRAY) {
366 assert(box->z + box->depth <= (int) resource->array_size);
367 }
368 else if (resource->target == PIPE_TEXTURE_CUBE) {
369 assert(box->z < 6);
370 }
371 else if (resource->target == PIPE_TEXTURE_CUBE_ARRAY) {
372 assert(box->z <= (int) resource->array_size);
373 }
374 else {
375 assert(box->z + box->depth <= (int) u_minify(resource->depth0, level));
376 }
377 }
378
379 /*
380 * Transfers, like other pipe operations, must happen in order, so flush the
381 * context if necessary.
382 */
383 if (!(usage & PIPE_TRANSFER_UNSYNCHRONIZED)) {
384 boolean read_only = !(usage & PIPE_TRANSFER_WRITE);
385 boolean do_not_block = !!(usage & PIPE_TRANSFER_DONTBLOCK);
386 if (!softpipe_flush_resource(pipe, resource,
387 level, box->depth > 1 ? -1 : box->z,
388 0, /* flush_flags */
389 read_only,
390 TRUE, /* cpu_access */
391 do_not_block)) {
392 /*
393 * It would have blocked, but state tracker requested no to.
394 */
395 assert(do_not_block);
396 return NULL;
397 }
398 }
399
400 spt = CALLOC_STRUCT(softpipe_transfer);
401 if (!spt)
402 return NULL;
403
404 pt = &spt->base;
405
406 pipe_resource_reference(&pt->resource, resource);
407 pt->level = level;
408 pt->usage = usage;
409 pt->box = *box;
410 pt->stride = spr->stride[level];
411 pt->layer_stride = spr->img_stride[level];
412
413 spt->offset = sp_get_tex_image_offset(spr, level, box->z);
414
415 spt->offset +=
416 box->y / util_format_get_blockheight(format) * spt->base.stride +
417 box->x / util_format_get_blockwidth(format) * util_format_get_blocksize(format);
418
419 /* resources backed by display target treated specially:
420 */
421 if (spr->dt) {
422 map = winsys->displaytarget_map(winsys, spr->dt, usage);
423 }
424 else {
425 map = spr->data;
426 }
427
428 if (map == NULL) {
429 pipe_resource_reference(&pt->resource, NULL);
430 FREE(spt);
431 return NULL;
432 }
433
434 *transfer = pt;
435 return map + spt->offset;
436 }
437
438
439 /**
440 * Unmap memory mapping for given pipe_transfer object.
441 */
442 static void
443 softpipe_transfer_unmap(struct pipe_context *pipe,
444 struct pipe_transfer *transfer)
445 {
446 struct softpipe_resource *spr;
447
448 assert(transfer->resource);
449 spr = softpipe_resource(transfer->resource);
450
451 if (spr->dt) {
452 /* display target */
453 struct sw_winsys *winsys = softpipe_screen(pipe->screen)->winsys;
454 winsys->displaytarget_unmap(winsys, spr->dt);
455 }
456
457 if (transfer->usage & PIPE_TRANSFER_WRITE) {
458 /* Mark the texture as dirty to expire the tile caches. */
459 spr->timestamp++;
460 }
461
462 pipe_resource_reference(&transfer->resource, NULL);
463 FREE(transfer);
464 }
465
466 /**
467 * Create buffer which wraps user-space data.
468 */
469 struct pipe_resource *
470 softpipe_user_buffer_create(struct pipe_screen *screen,
471 void *ptr,
472 unsigned bytes,
473 unsigned bind_flags)
474 {
475 struct softpipe_resource *spr;
476
477 spr = CALLOC_STRUCT(softpipe_resource);
478 if (!spr)
479 return NULL;
480
481 pipe_reference_init(&spr->base.reference, 1);
482 spr->base.screen = screen;
483 spr->base.format = PIPE_FORMAT_R8_UNORM; /* ?? */
484 spr->base.bind = bind_flags;
485 spr->base.usage = PIPE_USAGE_IMMUTABLE;
486 spr->base.flags = 0;
487 spr->base.width0 = bytes;
488 spr->base.height0 = 1;
489 spr->base.depth0 = 1;
490 spr->base.array_size = 1;
491 spr->userBuffer = TRUE;
492 spr->data = ptr;
493
494 return &spr->base;
495 }
496
497
498 void
499 softpipe_init_texture_funcs(struct pipe_context *pipe)
500 {
501 pipe->transfer_map = softpipe_transfer_map;
502 pipe->transfer_unmap = softpipe_transfer_unmap;
503
504 pipe->transfer_flush_region = u_default_transfer_flush_region;
505 pipe->transfer_inline_write = u_default_transfer_inline_write;
506
507 pipe->create_surface = softpipe_create_surface;
508 pipe->surface_destroy = softpipe_surface_destroy;
509 }
510
511
512 void
513 softpipe_init_screen_texture_funcs(struct pipe_screen *screen)
514 {
515 screen->resource_create = softpipe_resource_create;
516 screen->resource_destroy = softpipe_resource_destroy;
517 screen->resource_from_handle = softpipe_resource_from_handle;
518 screen->resource_get_handle = softpipe_resource_get_handle;
519 screen->can_create_resource = softpipe_can_create_resource;
520 }