1 /**************************************************************************
3 * Copyright 2006 VMware, Inc.
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
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.
26 **************************************************************************/
29 * Keith Whitwell <keithw@vmware.com>
30 * Michel Dänzer <daenzer@vmware.com>
33 #include "pipe/p_defines.h"
34 #include "util/u_inlines.h"
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 #include "util/u_surface.h"
42 #include "sp_context.h"
44 #include "sp_texture.h"
45 #include "sp_screen.h"
47 #include "state_tracker/sw_winsys.h"
51 * Conventional allocation path for non-display textures:
52 * Use a simple, maximally packed layout.
55 softpipe_resource_layout(struct pipe_screen
*screen
,
56 struct softpipe_resource
*spr
,
59 struct pipe_resource
*pt
= &spr
->base
;
61 unsigned width
= pt
->width0
;
62 unsigned height
= pt
->height0
;
63 unsigned depth
= pt
->depth0
;
64 uint64_t buffer_size
= 0;
66 for (level
= 0; level
<= pt
->last_level
; level
++) {
67 unsigned slices
, nblocksy
;
69 nblocksy
= util_format_get_nblocksy(pt
->format
, height
);
71 if (pt
->target
== PIPE_TEXTURE_CUBE
)
72 assert(pt
->array_size
== 6);
74 if (pt
->target
== PIPE_TEXTURE_3D
)
77 slices
= pt
->array_size
;
79 spr
->stride
[level
] = util_format_get_stride(pt
->format
, width
);
81 spr
->level_offset
[level
] = buffer_size
;
83 /* if row_stride * height > SP_MAX_TEXTURE_SIZE */
84 if ((uint64_t)spr
->stride
[level
] * nblocksy
> SP_MAX_TEXTURE_SIZE
) {
89 spr
->img_stride
[level
] = spr
->stride
[level
] * nblocksy
;
91 buffer_size
+= (uint64_t) spr
->img_stride
[level
] * slices
;
93 width
= u_minify(width
, 1);
94 height
= u_minify(height
, 1);
95 depth
= u_minify(depth
, 1);
98 if (buffer_size
> SP_MAX_TEXTURE_SIZE
)
102 spr
->data
= align_malloc(buffer_size
, 64);
103 return spr
->data
!= NULL
;
112 * Check the size of the texture specified by 'res'.
113 * \return TRUE if OK, FALSE if too large.
116 softpipe_can_create_resource(struct pipe_screen
*screen
,
117 const struct pipe_resource
*res
)
119 struct softpipe_resource spr
;
120 memset(&spr
, 0, sizeof(spr
));
122 return softpipe_resource_layout(screen
, &spr
, FALSE
);
127 * Texture layout for simple color buffers.
130 softpipe_displaytarget_layout(struct pipe_screen
*screen
,
131 struct softpipe_resource
*spr
,
132 const void *map_front_private
)
134 struct sw_winsys
*winsys
= softpipe_screen(screen
)->winsys
;
136 /* Round up the surface size to a multiple of the tile size?
138 spr
->dt
= winsys
->displaytarget_create(winsys
,
147 return spr
->dt
!= NULL
;
152 * Create new pipe_resource given the template information.
154 static struct pipe_resource
*
155 softpipe_resource_create_front(struct pipe_screen
*screen
,
156 const struct pipe_resource
*templat
,
157 const void *map_front_private
)
159 struct softpipe_resource
*spr
= CALLOC_STRUCT(softpipe_resource
);
163 assert(templat
->format
!= PIPE_FORMAT_NONE
);
165 spr
->base
= *templat
;
166 pipe_reference_init(&spr
->base
.reference
, 1);
167 spr
->base
.screen
= screen
;
169 spr
->pot
= (util_is_power_of_two(templat
->width0
) &&
170 util_is_power_of_two(templat
->height0
) &&
171 util_is_power_of_two(templat
->depth0
));
173 if (spr
->base
.bind
& (PIPE_BIND_DISPLAY_TARGET
|
176 if (!softpipe_displaytarget_layout(screen
, spr
, map_front_private
))
180 if (!softpipe_resource_layout(screen
, spr
, TRUE
))
191 static struct pipe_resource
*
192 softpipe_resource_create(struct pipe_screen
*screen
,
193 const struct pipe_resource
*templat
)
195 return softpipe_resource_create_front(screen
, templat
, NULL
);
199 softpipe_resource_destroy(struct pipe_screen
*pscreen
,
200 struct pipe_resource
*pt
)
202 struct softpipe_screen
*screen
= softpipe_screen(pscreen
);
203 struct softpipe_resource
*spr
= softpipe_resource(pt
);
207 struct sw_winsys
*winsys
= screen
->winsys
;
208 winsys
->displaytarget_destroy(winsys
, spr
->dt
);
210 else if (!spr
->userBuffer
) {
211 /* regular texture */
212 align_free(spr
->data
);
219 static struct pipe_resource
*
220 softpipe_resource_from_handle(struct pipe_screen
*screen
,
221 const struct pipe_resource
*templat
,
222 struct winsys_handle
*whandle
,
225 struct sw_winsys
*winsys
= softpipe_screen(screen
)->winsys
;
226 struct softpipe_resource
*spr
= CALLOC_STRUCT(softpipe_resource
);
230 spr
->base
= *templat
;
231 pipe_reference_init(&spr
->base
.reference
, 1);
232 spr
->base
.screen
= screen
;
234 spr
->pot
= (util_is_power_of_two(templat
->width0
) &&
235 util_is_power_of_two(templat
->height0
) &&
236 util_is_power_of_two(templat
->depth0
));
238 spr
->dt
= winsys
->displaytarget_from_handle(winsys
,
254 softpipe_resource_get_handle(struct pipe_screen
*screen
,
255 struct pipe_context
*ctx
,
256 struct pipe_resource
*pt
,
257 struct winsys_handle
*whandle
,
260 struct sw_winsys
*winsys
= softpipe_screen(screen
)->winsys
;
261 struct softpipe_resource
*spr
= softpipe_resource(pt
);
267 return winsys
->displaytarget_get_handle(winsys
, spr
->dt
, whandle
);
272 * Helper function to compute offset (in bytes) for a particular
273 * texture level/face/slice from the start of the buffer.
276 softpipe_get_tex_image_offset(const struct softpipe_resource
*spr
,
277 unsigned level
, unsigned layer
)
279 unsigned offset
= spr
->level_offset
[level
];
281 offset
+= layer
* spr
->img_stride
[level
];
288 * Get a pipe_surface "view" into a texture resource.
290 static struct pipe_surface
*
291 softpipe_create_surface(struct pipe_context
*pipe
,
292 struct pipe_resource
*pt
,
293 const struct pipe_surface
*surf_tmpl
)
295 struct pipe_surface
*ps
;
297 ps
= CALLOC_STRUCT(pipe_surface
);
299 pipe_reference_init(&ps
->reference
, 1);
300 pipe_resource_reference(&ps
->texture
, pt
);
302 ps
->format
= surf_tmpl
->format
;
303 if (pt
->target
!= PIPE_BUFFER
) {
304 assert(surf_tmpl
->u
.tex
.level
<= pt
->last_level
);
305 ps
->width
= u_minify(pt
->width0
, surf_tmpl
->u
.tex
.level
);
306 ps
->height
= u_minify(pt
->height0
, surf_tmpl
->u
.tex
.level
);
307 ps
->u
.tex
.level
= surf_tmpl
->u
.tex
.level
;
308 ps
->u
.tex
.first_layer
= surf_tmpl
->u
.tex
.first_layer
;
309 ps
->u
.tex
.last_layer
= surf_tmpl
->u
.tex
.last_layer
;
310 if (ps
->u
.tex
.first_layer
!= ps
->u
.tex
.last_layer
) {
311 debug_printf("creating surface with multiple layers, rendering to first layer only\n");
315 /* setting width as number of elements should get us correct renderbuffer width */
316 ps
->width
= surf_tmpl
->u
.buf
.last_element
- surf_tmpl
->u
.buf
.first_element
+ 1;
317 ps
->height
= pt
->height0
;
318 ps
->u
.buf
.first_element
= surf_tmpl
->u
.buf
.first_element
;
319 ps
->u
.buf
.last_element
= surf_tmpl
->u
.buf
.last_element
;
320 assert(ps
->u
.buf
.first_element
<= ps
->u
.buf
.last_element
);
321 assert(ps
->u
.buf
.last_element
< ps
->width
);
329 * Free a pipe_surface which was created with softpipe_create_surface().
332 softpipe_surface_destroy(struct pipe_context
*pipe
,
333 struct pipe_surface
*surf
)
335 /* Effectively do the texture_update work here - if texture images
336 * needed post-processing to put them into hardware layout, this is
337 * where it would happen. For softpipe, nothing to do.
339 assert(surf
->texture
);
340 pipe_resource_reference(&surf
->texture
, NULL
);
346 * Geta pipe_transfer object which is used for moving data in/out of
348 * \param pipe rendering context
349 * \param resource the resource to transfer in/out of
350 * \param level which mipmap level
351 * \param usage bitmask of PIPE_TRANSFER_x flags
352 * \param box the 1D/2D/3D region of interest
355 softpipe_transfer_map(struct pipe_context
*pipe
,
356 struct pipe_resource
*resource
,
359 const struct pipe_box
*box
,
360 struct pipe_transfer
**transfer
)
362 struct sw_winsys
*winsys
= softpipe_screen(pipe
->screen
)->winsys
;
363 struct softpipe_resource
*spr
= softpipe_resource(resource
);
364 struct softpipe_transfer
*spt
;
365 struct pipe_transfer
*pt
;
366 enum pipe_format format
= resource
->format
;
370 assert(level
<= resource
->last_level
);
372 /* make sure the requested region is in the image bounds */
373 assert(box
->x
+ box
->width
<= (int) u_minify(resource
->width0
, level
));
374 if (resource
->target
== PIPE_TEXTURE_1D_ARRAY
) {
375 assert(box
->y
+ box
->height
<= (int) resource
->array_size
);
378 assert(box
->y
+ box
->height
<= (int) u_minify(resource
->height0
, level
));
379 if (resource
->target
== PIPE_TEXTURE_2D_ARRAY
) {
380 assert(box
->z
+ box
->depth
<= (int) resource
->array_size
);
382 else if (resource
->target
== PIPE_TEXTURE_CUBE
) {
385 else if (resource
->target
== PIPE_TEXTURE_CUBE_ARRAY
) {
386 assert(box
->z
<= (int) resource
->array_size
);
389 assert(box
->z
+ box
->depth
<= (int) u_minify(resource
->depth0
, level
));
394 * Transfers, like other pipe operations, must happen in order, so flush the
395 * context if necessary.
397 if (!(usage
& PIPE_TRANSFER_UNSYNCHRONIZED
)) {
398 boolean read_only
= !(usage
& PIPE_TRANSFER_WRITE
);
399 boolean do_not_block
= !!(usage
& PIPE_TRANSFER_DONTBLOCK
);
400 if (!softpipe_flush_resource(pipe
, resource
,
401 level
, box
->depth
> 1 ? -1 : box
->z
,
404 TRUE
, /* cpu_access */
407 * It would have blocked, but state tracker requested no to.
409 assert(do_not_block
);
414 spt
= CALLOC_STRUCT(softpipe_transfer
);
420 pipe_resource_reference(&pt
->resource
, resource
);
424 pt
->stride
= spr
->stride
[level
];
425 pt
->layer_stride
= spr
->img_stride
[level
];
427 spt
->offset
= softpipe_get_tex_image_offset(spr
, level
, box
->z
);
430 box
->y
/ util_format_get_blockheight(format
) * spt
->base
.stride
+
431 box
->x
/ util_format_get_blockwidth(format
) * util_format_get_blocksize(format
);
433 /* resources backed by display target treated specially:
436 map
= winsys
->displaytarget_map(winsys
, spr
->dt
, usage
);
443 pipe_resource_reference(&pt
->resource
, NULL
);
449 return map
+ spt
->offset
;
454 * Unmap memory mapping for given pipe_transfer object.
457 softpipe_transfer_unmap(struct pipe_context
*pipe
,
458 struct pipe_transfer
*transfer
)
460 struct softpipe_resource
*spr
;
462 assert(transfer
->resource
);
463 spr
= softpipe_resource(transfer
->resource
);
467 struct sw_winsys
*winsys
= softpipe_screen(pipe
->screen
)->winsys
;
468 winsys
->displaytarget_unmap(winsys
, spr
->dt
);
471 if (transfer
->usage
& PIPE_TRANSFER_WRITE
) {
472 /* Mark the texture as dirty to expire the tile caches. */
476 pipe_resource_reference(&transfer
->resource
, NULL
);
481 * Create buffer which wraps user-space data.
483 struct pipe_resource
*
484 softpipe_user_buffer_create(struct pipe_screen
*screen
,
489 struct softpipe_resource
*spr
;
491 spr
= CALLOC_STRUCT(softpipe_resource
);
495 pipe_reference_init(&spr
->base
.reference
, 1);
496 spr
->base
.screen
= screen
;
497 spr
->base
.format
= PIPE_FORMAT_R8_UNORM
; /* ?? */
498 spr
->base
.bind
= bind_flags
;
499 spr
->base
.usage
= PIPE_USAGE_IMMUTABLE
;
501 spr
->base
.width0
= bytes
;
502 spr
->base
.height0
= 1;
503 spr
->base
.depth0
= 1;
504 spr
->base
.array_size
= 1;
505 spr
->userBuffer
= TRUE
;
513 softpipe_init_texture_funcs(struct pipe_context
*pipe
)
515 pipe
->transfer_map
= softpipe_transfer_map
;
516 pipe
->transfer_unmap
= softpipe_transfer_unmap
;
518 pipe
->transfer_flush_region
= u_default_transfer_flush_region
;
519 pipe
->buffer_subdata
= u_default_buffer_subdata
;
520 pipe
->texture_subdata
= u_default_texture_subdata
;
522 pipe
->create_surface
= softpipe_create_surface
;
523 pipe
->surface_destroy
= softpipe_surface_destroy
;
524 pipe
->clear_texture
= util_clear_texture
;
529 softpipe_init_screen_texture_funcs(struct pipe_screen
*screen
)
531 screen
->resource_create
= softpipe_resource_create
;
532 screen
->resource_create_front
= softpipe_resource_create_front
;
533 screen
->resource_destroy
= softpipe_resource_destroy
;
534 screen
->resource_from_handle
= softpipe_resource_from_handle
;
535 screen
->resource_get_handle
= softpipe_resource_get_handle
;
536 screen
->can_create_resource
= softpipe_can_create_resource
;