Merge branch '7.8'
[mesa.git] / src / gallium / drivers / llvmpipe / lp_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_context.h"
34 #include "pipe/p_defines.h"
35 #include "util/u_inlines.h"
36
37 #include "util/u_format.h"
38 #include "util/u_math.h"
39 #include "util/u_memory.h"
40 #include "util/u_transfer.h"
41
42 #include "lp_context.h"
43 #include "lp_screen.h"
44 #include "lp_flush.h"
45 #include "lp_texture.h"
46 #include "lp_setup.h"
47 #include "lp_tile_size.h"
48 #include "state_tracker/sw_winsys.h"
49
50
51 /**
52 * Conventional allocation path for non-display textures:
53 * Simple, maximally packed layout.
54 */
55 static boolean
56 llvmpipe_resource_layout(struct llvmpipe_screen *screen,
57 struct llvmpipe_resource *lpt)
58 {
59 struct pipe_resource *pt = &lpt->base;
60 unsigned level;
61 unsigned width = pt->width0;
62 unsigned height = pt->height0;
63 unsigned depth = pt->depth0;
64 unsigned buffer_size = 0;
65
66 for (level = 0; level <= pt->last_level; level++) {
67 unsigned nblocksx, nblocksy;
68
69 /* Allocate storage for whole quads. This is particularly important
70 * for depth surfaces, which are currently stored in a swizzled format.
71 */
72 nblocksx = util_format_get_nblocksx(pt->format, align(width, TILE_SIZE));
73 nblocksy = util_format_get_nblocksy(pt->format, align(height, TILE_SIZE));
74
75 lpt->stride[level] = align(nblocksx * util_format_get_blocksize(pt->format), 16);
76
77 lpt->level_offset[level] = buffer_size;
78
79 buffer_size += (nblocksy *
80 ((pt->target == PIPE_TEXTURE_CUBE) ? 6 : depth) *
81 lpt->stride[level]);
82
83 width = u_minify(width, 1);
84 height = u_minify(height, 1);
85 depth = u_minify(depth, 1);
86 }
87
88 lpt->data = align_malloc(buffer_size, 16);
89
90 return lpt->data != NULL;
91 }
92
93
94
95 static boolean
96 llvmpipe_displaytarget_layout(struct llvmpipe_screen *screen,
97 struct llvmpipe_resource *lpt)
98 {
99 struct sw_winsys *winsys = screen->winsys;
100
101 /* Round up the surface size to a multiple of the tile size to
102 * avoid tile clipping.
103 */
104 unsigned width = align(lpt->base.width0, TILE_SIZE);
105 unsigned height = align(lpt->base.height0, TILE_SIZE);
106
107 lpt->dt = winsys->displaytarget_create(winsys,
108 lpt->base.bind,
109 lpt->base.format,
110 width, height,
111 16,
112 &lpt->stride[0] );
113
114 return lpt->dt != NULL;
115 }
116
117
118 static struct pipe_resource *
119 llvmpipe_resource_create(struct pipe_screen *_screen,
120 const struct pipe_resource *templat)
121 {
122 struct llvmpipe_screen *screen = llvmpipe_screen(_screen);
123 struct llvmpipe_resource *lpt = CALLOC_STRUCT(llvmpipe_resource);
124 if (!lpt)
125 return NULL;
126
127 lpt->base = *templat;
128 pipe_reference_init(&lpt->base.reference, 1);
129 lpt->base.screen = &screen->base;
130
131 if (lpt->base.bind & (PIPE_BIND_DISPLAY_TARGET |
132 PIPE_BIND_SCANOUT |
133 PIPE_BIND_SHARED)) {
134 if (!llvmpipe_displaytarget_layout(screen, lpt))
135 goto fail;
136 }
137 else {
138 if (!llvmpipe_resource_layout(screen, lpt))
139 goto fail;
140 }
141
142 return &lpt->base;
143
144 fail:
145 FREE(lpt);
146 return NULL;
147 }
148
149
150 static void
151 llvmpipe_resource_destroy(struct pipe_screen *pscreen,
152 struct pipe_resource *pt)
153 {
154 struct llvmpipe_screen *screen = llvmpipe_screen(pscreen);
155 struct llvmpipe_resource *lpt = llvmpipe_resource(pt);
156
157 if (lpt->dt) {
158 /* display target */
159 struct sw_winsys *winsys = screen->winsys;
160 winsys->displaytarget_destroy(winsys, lpt->dt);
161 }
162 else if (!lpt->userBuffer) {
163 /* regular texture */
164 align_free(lpt->data);
165 }
166
167 FREE(lpt);
168 }
169
170
171 /**
172 * Map a texture. Without any synchronization.
173 */
174 void *
175 llvmpipe_resource_map(struct pipe_resource *texture,
176 unsigned usage,
177 unsigned face,
178 unsigned level,
179 unsigned zslice)
180 {
181 struct llvmpipe_resource *lpt = llvmpipe_resource(texture);
182 uint8_t *map;
183
184 if (lpt->dt) {
185 /* display target */
186 struct llvmpipe_screen *screen = llvmpipe_screen(texture->screen);
187 struct sw_winsys *winsys = screen->winsys;
188
189 assert(face == 0);
190 assert(level == 0);
191 assert(zslice == 0);
192
193 /* FIXME: keep map count? */
194 map = winsys->displaytarget_map(winsys, lpt->dt, usage);
195 }
196 else {
197 /* regular texture */
198 unsigned offset;
199 unsigned stride;
200
201 map = lpt->data;
202
203 assert(level < LP_MAX_TEXTURE_2D_LEVELS);
204
205 offset = lpt->level_offset[level];
206 stride = lpt->stride[level];
207
208 /* XXX shouldn't that rather be
209 tex_height = align(u_minify(texture->height0, level), 2)
210 to account for alignment done in llvmpipe_resource_layout ?
211 */
212 if (texture->target == PIPE_TEXTURE_CUBE) {
213 unsigned tex_height = u_minify(texture->height0, level);
214 offset += face * util_format_get_nblocksy(texture->format, tex_height) * stride;
215 }
216 else if (texture->target == PIPE_TEXTURE_3D) {
217 unsigned tex_height = u_minify(texture->height0, level);
218 offset += zslice * util_format_get_nblocksy(texture->format, tex_height) * stride;
219 }
220 else {
221 assert(face == 0);
222 assert(zslice == 0);
223 }
224
225 map += offset;
226 }
227
228 return map;
229 }
230
231
232 /**
233 * Unmap a texture. Without any synchronization.
234 */
235 void
236 llvmpipe_resource_unmap(struct pipe_resource *texture,
237 unsigned face,
238 unsigned level,
239 unsigned zslice)
240 {
241 struct llvmpipe_resource *lpt = llvmpipe_resource(texture);
242
243 if (lpt->dt) {
244 /* display target */
245 struct llvmpipe_screen *lp_screen = llvmpipe_screen(texture->screen);
246 struct sw_winsys *winsys = lp_screen->winsys;
247
248 assert(face == 0);
249 assert(level == 0);
250 assert(zslice == 0);
251
252 winsys->displaytarget_unmap(winsys, lpt->dt);
253 }
254 }
255
256
257 static struct pipe_resource *
258 llvmpipe_resource_from_handle(struct pipe_screen *screen,
259 const struct pipe_resource *template,
260 struct winsys_handle *whandle)
261 {
262 struct sw_winsys *winsys = llvmpipe_screen(screen)->winsys;
263 struct llvmpipe_resource *lpt = CALLOC_STRUCT(llvmpipe_resource);
264 if (!lpt)
265 return NULL;
266
267 lpt->base = *template;
268 pipe_reference_init(&lpt->base.reference, 1);
269 lpt->base.screen = screen;
270
271 lpt->dt = winsys->displaytarget_from_handle(winsys,
272 template,
273 whandle,
274 &lpt->stride[0]);
275 if (!lpt->dt)
276 goto fail;
277
278 return &lpt->base;
279
280 fail:
281 FREE(lpt);
282 return NULL;
283 }
284
285
286 static boolean
287 llvmpipe_resource_get_handle(struct pipe_screen *screen,
288 struct pipe_resource *pt,
289 struct winsys_handle *whandle)
290 {
291 struct sw_winsys *winsys = llvmpipe_screen(screen)->winsys;
292 struct llvmpipe_resource *lpt = llvmpipe_resource(pt);
293
294 assert(lpt->dt);
295 if (!lpt->dt)
296 return FALSE;
297
298 return winsys->displaytarget_get_handle(winsys, lpt->dt, whandle);
299 }
300
301
302 static struct pipe_surface *
303 llvmpipe_get_tex_surface(struct pipe_screen *screen,
304 struct pipe_resource *pt,
305 unsigned face, unsigned level, unsigned zslice,
306 unsigned usage)
307 {
308 struct pipe_surface *ps;
309
310 assert(level <= pt->last_level);
311
312 ps = CALLOC_STRUCT(pipe_surface);
313 if (ps) {
314 pipe_reference_init(&ps->reference, 1);
315 pipe_resource_reference(&ps->texture, pt);
316 ps->format = pt->format;
317 ps->width = u_minify(pt->width0, level);
318 ps->height = u_minify(pt->height0, level);
319 ps->usage = usage;
320
321 ps->face = face;
322 ps->level = level;
323 ps->zslice = zslice;
324 }
325 return ps;
326 }
327
328
329 static void
330 llvmpipe_tex_surface_destroy(struct pipe_surface *surf)
331 {
332 /* Effectively do the texture_update work here - if texture images
333 * needed post-processing to put them into hardware layout, this is
334 * where it would happen. For llvmpipe, nothing to do.
335 */
336 assert(surf->texture);
337 pipe_resource_reference(&surf->texture, NULL);
338 FREE(surf);
339 }
340
341
342 static struct pipe_transfer *
343 llvmpipe_get_transfer(struct pipe_context *pipe,
344 struct pipe_resource *resource,
345 struct pipe_subresource sr,
346 unsigned usage,
347 const struct pipe_box *box)
348 {
349 struct llvmpipe_resource *lptex = llvmpipe_resource(resource);
350 struct llvmpipe_transfer *lpt;
351
352 assert(resource);
353 assert(sr.level <= resource->last_level);
354
355 lpt = CALLOC_STRUCT(llvmpipe_transfer);
356 if (lpt) {
357 struct pipe_transfer *pt = &lpt->base;
358 pipe_resource_reference(&pt->resource, resource);
359 pt->box = *box;
360 pt->sr = sr;
361 pt->stride = lptex->stride[sr.level];
362 pt->usage = usage;
363
364 return pt;
365 }
366 return NULL;
367 }
368
369
370 static void
371 llvmpipe_transfer_destroy(struct pipe_context *pipe,
372 struct pipe_transfer *transfer)
373 {
374 /* Effectively do the texture_update work here - if texture images
375 * needed post-processing to put them into hardware layout, this is
376 * where it would happen. For llvmpipe, nothing to do.
377 */
378 assert (transfer->resource);
379 pipe_resource_reference(&transfer->resource, NULL);
380 FREE(transfer);
381 }
382
383
384 static void *
385 llvmpipe_transfer_map( struct pipe_context *pipe,
386 struct pipe_transfer *transfer )
387 {
388 struct llvmpipe_screen *screen = llvmpipe_screen(pipe->screen);
389 ubyte *map;
390 struct llvmpipe_resource *lpt;
391 enum pipe_format format;
392
393 assert(transfer->resource);
394 lpt = llvmpipe_resource(transfer->resource);
395 format = lpt->base.format;
396
397 /*
398 * Transfers, like other pipe operations, must happen in order, so flush the
399 * context if necessary.
400 */
401 llvmpipe_flush_texture(pipe,
402 transfer->resource,
403 transfer->sr.face,
404 transfer->sr.level,
405 0, /* flush_flags */
406 !(transfer->usage & PIPE_TRANSFER_WRITE), /* read_only */
407 TRUE, /* cpu_access */
408 FALSE); /* do_not_flush */
409
410 map = llvmpipe_resource_map(transfer->resource,
411 transfer->usage,
412 transfer->sr.face,
413 transfer->sr.level,
414 transfer->box.z);
415
416 /* May want to different things here depending on read/write nature
417 * of the map:
418 */
419 if (transfer->usage & PIPE_TRANSFER_WRITE) {
420 /* Do something to notify sharing contexts of a texture change.
421 */
422 screen->timestamp++;
423 }
424
425 map +=
426 transfer->box.y / util_format_get_blockheight(format) * transfer->stride +
427 transfer->box.x / util_format_get_blockwidth(format) * util_format_get_blocksize(format);
428
429 return map;
430 }
431
432
433 static void
434 llvmpipe_transfer_unmap(struct pipe_context *pipe,
435 struct pipe_transfer *transfer)
436 {
437 assert(transfer->resource);
438
439 llvmpipe_resource_unmap(transfer->resource,
440 transfer->sr.face,
441 transfer->sr.level,
442 transfer->box.z);
443 }
444
445 static unsigned int
446 llvmpipe_is_resource_referenced( struct pipe_context *pipe,
447 struct pipe_resource *presource,
448 unsigned face, unsigned level)
449 {
450 struct llvmpipe_context *llvmpipe = llvmpipe_context( pipe );
451
452 if (presource->target == PIPE_BUFFER)
453 return PIPE_UNREFERENCED;
454
455 return lp_setup_is_resource_referenced(llvmpipe->setup, presource);
456 }
457
458
459
460 /**
461 * Create buffer which wraps user-space data.
462 */
463 static struct pipe_resource *
464 llvmpipe_user_buffer_create(struct pipe_screen *screen,
465 void *ptr,
466 unsigned bytes,
467 unsigned bind_flags)
468 {
469 struct llvmpipe_resource *buffer;
470
471 buffer = CALLOC_STRUCT(llvmpipe_resource);
472 if(!buffer)
473 return NULL;
474
475 pipe_reference_init(&buffer->base.reference, 1);
476 buffer->base.screen = screen;
477 buffer->base.format = PIPE_FORMAT_R8_UNORM; /* ?? */
478 buffer->base.bind = bind_flags;
479 buffer->base._usage = PIPE_USAGE_IMMUTABLE;
480 buffer->base.flags = 0;
481 buffer->base.width0 = bytes;
482 buffer->base.height0 = 1;
483 buffer->base.depth0 = 1;
484 buffer->userBuffer = TRUE;
485 buffer->data = ptr;
486
487 return &buffer->base;
488 }
489
490
491 void
492 llvmpipe_init_screen_resource_funcs(struct pipe_screen *screen)
493 {
494 screen->resource_create = llvmpipe_resource_create;
495 screen->resource_destroy = llvmpipe_resource_destroy;
496 screen->resource_from_handle = llvmpipe_resource_from_handle;
497 screen->resource_get_handle = llvmpipe_resource_get_handle;
498 screen->user_buffer_create = llvmpipe_user_buffer_create;
499
500 screen->get_tex_surface = llvmpipe_get_tex_surface;
501 screen->tex_surface_destroy = llvmpipe_tex_surface_destroy;
502 }
503
504
505 void
506 llvmpipe_init_context_resource_funcs(struct pipe_context *pipe)
507 {
508 pipe->get_transfer = llvmpipe_get_transfer;
509 pipe->transfer_destroy = llvmpipe_transfer_destroy;
510 pipe->transfer_map = llvmpipe_transfer_map;
511 pipe->transfer_unmap = llvmpipe_transfer_unmap;
512 pipe->is_resource_referenced = llvmpipe_is_resource_referenced;
513
514 pipe->transfer_flush_region = u_default_transfer_flush_region;
515 pipe->transfer_inline_write = u_default_transfer_inline_write;
516 }