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