1 /**************************************************************************
2 *
3 * Copyright 2007 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 #ifndef U_INLINES_H
29 #define U_INLINES_H
30
31 #include "pipe/p_context.h"
32 #include "pipe/p_defines.h"
33 #include "pipe/p_shader_tokens.h"
34 #include "pipe/p_state.h"
35 #include "pipe/p_screen.h"
36 #include "util/u_debug.h"
37 #include "util/u_debug_describe.h"
38 #include "util/u_debug_refcnt.h"
39 #include "util/u_atomic.h"
40 #include "util/u_box.h"
41 #include "util/u_math.h"
42
43
44 #ifdef __cplusplus
45 extern "C" {
46 #endif
47
48
49 /*
50 * Reference counting helper functions.
51 */
52
53
54 static inline void
pipe_reference_init(struct pipe_reference * dst,unsigned count)55 pipe_reference_init(struct pipe_reference *dst, unsigned count)
56 {
57 p_atomic_set(&dst->count, count);
58 }
59
60 static inline boolean
pipe_is_referenced(struct pipe_reference * src)61 pipe_is_referenced(struct pipe_reference *src)
62 {
63 return p_atomic_read(&src->count) != 0;
64 }
65
66 /**
67 * Update reference counting.
68 * The old thing pointed to, if any, will be unreferenced.
69 * Both 'dst' and 'src' may be NULL.
70 * \return TRUE if the object's refcount hits zero and should be destroyed.
71 */
72 static inline boolean
pipe_reference_described(struct pipe_reference * dst,struct pipe_reference * src,debug_reference_descriptor get_desc)73 pipe_reference_described(struct pipe_reference *dst,
74 struct pipe_reference *src,
75 debug_reference_descriptor get_desc)
76 {
77 if (dst != src) {
78 /* bump the src.count first */
79 if (src) {
80 ASSERTED int count = p_atomic_inc_return(&src->count);
81 assert(count != 1); /* src had to be referenced */
82 debug_reference(src, get_desc, 1);
83 }
84
85 if (dst) {
86 int count = p_atomic_dec_return(&dst->count);
87 assert(count != -1); /* dst had to be referenced */
88 debug_reference(dst, get_desc, -1);
89 if (!count)
90 return true;
91 }
92 }
93
94 return false;
95 }
96
97 static inline boolean
pipe_reference(struct pipe_reference * dst,struct pipe_reference * src)98 pipe_reference(struct pipe_reference *dst, struct pipe_reference *src)
99 {
100 return pipe_reference_described(dst, src,
101 (debug_reference_descriptor)
102 debug_describe_reference);
103 }
104
105 static inline void
pipe_surface_reference(struct pipe_surface ** dst,struct pipe_surface * src)106 pipe_surface_reference(struct pipe_surface **dst, struct pipe_surface *src)
107 {
108 struct pipe_surface *old_dst = *dst;
109
110 if (pipe_reference_described(old_dst ? &old_dst->reference : NULL,
111 src ? &src->reference : NULL,
112 (debug_reference_descriptor)
113 debug_describe_surface))
114 old_dst->context->surface_destroy(old_dst->context, old_dst);
115 *dst = src;
116 }
117
118 /**
119 * Similar to pipe_surface_reference() but always set the pointer to NULL
120 * and pass in an explicit context. The explicit context avoids the problem
121 * of using a deleted context's surface_destroy() method when freeing a surface
122 * that's shared by multiple contexts.
123 */
124 static inline void
pipe_surface_release(struct pipe_context * pipe,struct pipe_surface ** ptr)125 pipe_surface_release(struct pipe_context *pipe, struct pipe_surface **ptr)
126 {
127 struct pipe_surface *old = *ptr;
128
129 if (pipe_reference_described(&old->reference, NULL,
130 (debug_reference_descriptor)
131 debug_describe_surface))
132 pipe->surface_destroy(pipe, old);
133 *ptr = NULL;
134 }
135
136
137 static inline void
pipe_resource_reference(struct pipe_resource ** dst,struct pipe_resource * src)138 pipe_resource_reference(struct pipe_resource **dst, struct pipe_resource *src)
139 {
140 struct pipe_resource *old_dst = *dst;
141
142 if (pipe_reference_described(old_dst ? &old_dst->reference : NULL,
143 src ? &src->reference : NULL,
144 (debug_reference_descriptor)
145 debug_describe_resource)) {
146 /* Avoid recursion, which would prevent inlining this function */
147 do {
148 struct pipe_resource *next = old_dst->next;
149
150 old_dst->screen->resource_destroy(old_dst->screen, old_dst);
151 old_dst = next;
152 } while (pipe_reference_described(old_dst ? &old_dst->reference : NULL,
153 NULL,
154 (debug_reference_descriptor)
155 debug_describe_resource));
156 }
157 *dst = src;
158 }
159
160 /**
161 * Same as pipe_surface_release, but used when pipe_context doesn't exist
162 * anymore.
163 */
164 static inline void
pipe_surface_release_no_context(struct pipe_surface ** ptr)165 pipe_surface_release_no_context(struct pipe_surface **ptr)
166 {
167 struct pipe_surface *surf = *ptr;
168
169 if (pipe_reference_described(&surf->reference, NULL,
170 (debug_reference_descriptor)
171 debug_describe_surface)) {
172 /* trivially destroy pipe_surface */
173 pipe_resource_reference(&surf->texture, NULL);
174 free(surf);
175 }
176 *ptr = NULL;
177 }
178
179 /**
180 * Set *dst to \p src with proper reference counting.
181 *
182 * The caller must guarantee that \p src and *dst were created in
183 * the same context (if they exist), and that this must be the current context.
184 */
185 static inline void
pipe_sampler_view_reference(struct pipe_sampler_view ** dst,struct pipe_sampler_view * src)186 pipe_sampler_view_reference(struct pipe_sampler_view **dst,
187 struct pipe_sampler_view *src)
188 {
189 struct pipe_sampler_view *old_dst = *dst;
190
191 if (pipe_reference_described(old_dst ? &old_dst->reference : NULL,
192 src ? &src->reference : NULL,
193 (debug_reference_descriptor)
194 debug_describe_sampler_view))
195 old_dst->context->sampler_view_destroy(old_dst->context, old_dst);
196 *dst = src;
197 }
198
199 static inline void
pipe_so_target_reference(struct pipe_stream_output_target ** dst,struct pipe_stream_output_target * src)200 pipe_so_target_reference(struct pipe_stream_output_target **dst,
201 struct pipe_stream_output_target *src)
202 {
203 struct pipe_stream_output_target *old_dst = *dst;
204
205 if (pipe_reference_described(old_dst ? &old_dst->reference : NULL,
206 src ? &src->reference : NULL,
207 (debug_reference_descriptor)debug_describe_so_target))
208 old_dst->context->stream_output_target_destroy(old_dst->context, old_dst);
209 *dst = src;
210 }
211
212 static inline void
pipe_vertex_buffer_unreference(struct pipe_vertex_buffer * dst)213 pipe_vertex_buffer_unreference(struct pipe_vertex_buffer *dst)
214 {
215 if (dst->is_user_buffer)
216 dst->buffer.user = NULL;
217 else
218 pipe_resource_reference(&dst->buffer.resource, NULL);
219 }
220
221 static inline void
pipe_vertex_buffer_reference(struct pipe_vertex_buffer * dst,const struct pipe_vertex_buffer * src)222 pipe_vertex_buffer_reference(struct pipe_vertex_buffer *dst,
223 const struct pipe_vertex_buffer *src)
224 {
225 pipe_vertex_buffer_unreference(dst);
226 if (!src->is_user_buffer)
227 pipe_resource_reference(&dst->buffer.resource, src->buffer.resource);
228 memcpy(dst, src, sizeof(*src));
229 }
230
231 static inline void
pipe_surface_reset(struct pipe_context * ctx,struct pipe_surface * ps,struct pipe_resource * pt,unsigned level,unsigned layer)232 pipe_surface_reset(struct pipe_context *ctx, struct pipe_surface* ps,
233 struct pipe_resource *pt, unsigned level, unsigned layer)
234 {
235 pipe_resource_reference(&ps->texture, pt);
236 ps->format = pt->format;
237 ps->width = u_minify(pt->width0, level);
238 ps->height = u_minify(pt->height0, level);
239 ps->u.tex.level = level;
240 ps->u.tex.first_layer = ps->u.tex.last_layer = layer;
241 ps->context = ctx;
242 }
243
244 static inline void
pipe_surface_init(struct pipe_context * ctx,struct pipe_surface * ps,struct pipe_resource * pt,unsigned level,unsigned layer)245 pipe_surface_init(struct pipe_context *ctx, struct pipe_surface* ps,
246 struct pipe_resource *pt, unsigned level, unsigned layer)
247 {
248 ps->texture = 0;
249 pipe_reference_init(&ps->reference, 1);
250 pipe_surface_reset(ctx, ps, pt, level, layer);
251 }
252
253 /* Return true if the surfaces are equal. */
254 static inline boolean
pipe_surface_equal(struct pipe_surface * s1,struct pipe_surface * s2)255 pipe_surface_equal(struct pipe_surface *s1, struct pipe_surface *s2)
256 {
257 return s1->texture == s2->texture &&
258 s1->format == s2->format &&
259 (s1->texture->target != PIPE_BUFFER ||
260 (s1->u.buf.first_element == s2->u.buf.first_element &&
261 s1->u.buf.last_element == s2->u.buf.last_element)) &&
262 (s1->texture->target == PIPE_BUFFER ||
263 (s1->u.tex.level == s2->u.tex.level &&
264 s1->u.tex.first_layer == s2->u.tex.first_layer &&
265 s1->u.tex.last_layer == s2->u.tex.last_layer));
266 }
267
268 /*
269 * Convenience wrappers for screen buffer functions.
270 */
271
272
273 /**
274 * Create a new resource.
275 * \param bind bitmask of PIPE_BIND_x flags
276 * \param usage a PIPE_USAGE_x value
277 */
278 static inline struct pipe_resource *
pipe_buffer_create(struct pipe_screen * screen,unsigned bind,enum pipe_resource_usage usage,unsigned size)279 pipe_buffer_create(struct pipe_screen *screen,
280 unsigned bind,
281 enum pipe_resource_usage usage,
282 unsigned size)
283 {
284 struct pipe_resource buffer;
285 memset(&buffer, 0, sizeof buffer);
286 buffer.target = PIPE_BUFFER;
287 buffer.format = PIPE_FORMAT_R8_UNORM; /* want TYPELESS or similar */
288 buffer.bind = bind;
289 buffer.usage = usage;
290 buffer.flags = 0;
291 buffer.width0 = size;
292 buffer.height0 = 1;
293 buffer.depth0 = 1;
294 buffer.array_size = 1;
295 return screen->resource_create(screen, &buffer);
296 }
297
298
299 static inline struct pipe_resource *
pipe_buffer_create_const0(struct pipe_screen * screen,unsigned bind,enum pipe_resource_usage usage,unsigned size)300 pipe_buffer_create_const0(struct pipe_screen *screen,
301 unsigned bind,
302 enum pipe_resource_usage usage,
303 unsigned size)
304 {
305 struct pipe_resource buffer;
306 memset(&buffer, 0, sizeof buffer);
307 buffer.target = PIPE_BUFFER;
308 buffer.format = PIPE_FORMAT_R8_UNORM;
309 buffer.bind = bind;
310 buffer.usage = usage;
311 buffer.flags = screen->get_param(screen, PIPE_CAP_CONSTBUF0_FLAGS);
312 buffer.width0 = size;
313 buffer.height0 = 1;
314 buffer.depth0 = 1;
315 buffer.array_size = 1;
316 return screen->resource_create(screen, &buffer);
317 }
318
319
320 /**
321 * Map a range of a resource.
322 * \param offset start of region, in bytes
323 * \param length size of region, in bytes
324 * \param access bitmask of PIPE_MAP_x flags
325 * \param transfer returns a transfer object
326 */
327 static inline void *
pipe_buffer_map_range(struct pipe_context * pipe,struct pipe_resource * buffer,unsigned offset,unsigned length,unsigned access,struct pipe_transfer ** transfer)328 pipe_buffer_map_range(struct pipe_context *pipe,
329 struct pipe_resource *buffer,
330 unsigned offset,
331 unsigned length,
332 unsigned access,
333 struct pipe_transfer **transfer)
334 {
335 struct pipe_box box;
336 void *map;
337
338 assert(offset < buffer->width0);
339 assert(offset + length <= buffer->width0);
340 assert(length);
341
342 u_box_1d(offset, length, &box);
343
344 map = pipe->transfer_map(pipe, buffer, 0, access, &box, transfer);
345 if (!map) {
346 return NULL;
347 }
348
349 return map;
350 }
351
352
353 /**
354 * Map whole resource.
355 * \param access bitmask of PIPE_MAP_x flags
356 * \param transfer returns a transfer object
357 */
358 static inline void *
pipe_buffer_map(struct pipe_context * pipe,struct pipe_resource * buffer,unsigned access,struct pipe_transfer ** transfer)359 pipe_buffer_map(struct pipe_context *pipe,
360 struct pipe_resource *buffer,
361 unsigned access,
362 struct pipe_transfer **transfer)
363 {
364 return pipe_buffer_map_range(pipe, buffer, 0, buffer->width0,
365 access, transfer);
366 }
367
368
369 static inline void
pipe_buffer_unmap(struct pipe_context * pipe,struct pipe_transfer * transfer)370 pipe_buffer_unmap(struct pipe_context *pipe,
371 struct pipe_transfer *transfer)
372 {
373 pipe->transfer_unmap(pipe, transfer);
374 }
375
376 static inline void
pipe_buffer_flush_mapped_range(struct pipe_context * pipe,struct pipe_transfer * transfer,unsigned offset,unsigned length)377 pipe_buffer_flush_mapped_range(struct pipe_context *pipe,
378 struct pipe_transfer *transfer,
379 unsigned offset,
380 unsigned length)
381 {
382 struct pipe_box box;
383 int transfer_offset;
384
385 assert(length);
386 assert(transfer->box.x <= (int) offset);
387 assert((int) (offset + length) <= transfer->box.x + transfer->box.width);
388
389 /* Match old screen->buffer_flush_mapped_range() behaviour, where
390 * offset parameter is relative to the start of the buffer, not the
391 * mapped range.
392 */
393 transfer_offset = offset - transfer->box.x;
394
395 u_box_1d(transfer_offset, length, &box);
396
397 pipe->transfer_flush_region(pipe, transfer, &box);
398 }
399
400 static inline void
pipe_buffer_write(struct pipe_context * pipe,struct pipe_resource * buf,unsigned offset,unsigned size,const void * data)401 pipe_buffer_write(struct pipe_context *pipe,
402 struct pipe_resource *buf,
403 unsigned offset,
404 unsigned size,
405 const void *data)
406 {
407 /* Don't set any other usage bits. Drivers should derive them. */
408 pipe->buffer_subdata(pipe, buf, PIPE_MAP_WRITE, offset, size, data);
409 }
410
411 /**
412 * Special case for writing non-overlapping ranges.
413 *
414 * We can avoid GPU/CPU synchronization when writing range that has never
415 * been written before.
416 */
417 static inline void
pipe_buffer_write_nooverlap(struct pipe_context * pipe,struct pipe_resource * buf,unsigned offset,unsigned size,const void * data)418 pipe_buffer_write_nooverlap(struct pipe_context *pipe,
419 struct pipe_resource *buf,
420 unsigned offset, unsigned size,
421 const void *data)
422 {
423 pipe->buffer_subdata(pipe, buf,
424 (PIPE_MAP_WRITE |
425 PIPE_MAP_UNSYNCHRONIZED),
426 offset, size, data);
427 }
428
429
430 /**
431 * Create a new resource and immediately put data into it
432 * \param bind bitmask of PIPE_BIND_x flags
433 * \param usage bitmask of PIPE_USAGE_x flags
434 */
435 static inline struct pipe_resource *
pipe_buffer_create_with_data(struct pipe_context * pipe,unsigned bind,enum pipe_resource_usage usage,unsigned size,const void * ptr)436 pipe_buffer_create_with_data(struct pipe_context *pipe,
437 unsigned bind,
438 enum pipe_resource_usage usage,
439 unsigned size,
440 const void *ptr)
441 {
442 struct pipe_resource *res = pipe_buffer_create(pipe->screen,
443 bind, usage, size);
444 pipe_buffer_write_nooverlap(pipe, res, 0, size, ptr);
445 return res;
446 }
447
448 static inline void
pipe_buffer_read(struct pipe_context * pipe,struct pipe_resource * buf,unsigned offset,unsigned size,void * data)449 pipe_buffer_read(struct pipe_context *pipe,
450 struct pipe_resource *buf,
451 unsigned offset,
452 unsigned size,
453 void *data)
454 {
455 struct pipe_transfer *src_transfer;
456 ubyte *map;
457
458 map = (ubyte *) pipe_buffer_map_range(pipe,
459 buf,
460 offset, size,
461 PIPE_MAP_READ,
462 &src_transfer);
463 if (!map)
464 return;
465
466 memcpy(data, map, size);
467 pipe_buffer_unmap(pipe, src_transfer);
468 }
469
470
471 /**
472 * Map a resource for reading/writing.
473 * \param access bitmask of PIPE_MAP_x flags
474 */
475 static inline void *
pipe_transfer_map(struct pipe_context * context,struct pipe_resource * resource,unsigned level,unsigned layer,unsigned access,unsigned x,unsigned y,unsigned w,unsigned h,struct pipe_transfer ** transfer)476 pipe_transfer_map(struct pipe_context *context,
477 struct pipe_resource *resource,
478 unsigned level, unsigned layer,
479 unsigned access,
480 unsigned x, unsigned y,
481 unsigned w, unsigned h,
482 struct pipe_transfer **transfer)
483 {
484 struct pipe_box box;
485 u_box_2d_zslice(x, y, layer, w, h, &box);
486 return context->transfer_map(context,
487 resource,
488 level,
489 access,
490 &box, transfer);
491 }
492
493
494 /**
495 * Map a 3D (texture) resource for reading/writing.
496 * \param access bitmask of PIPE_MAP_x flags
497 */
498 static inline void *
pipe_transfer_map_3d(struct pipe_context * context,struct pipe_resource * resource,unsigned level,unsigned access,unsigned x,unsigned y,unsigned z,unsigned w,unsigned h,unsigned d,struct pipe_transfer ** transfer)499 pipe_transfer_map_3d(struct pipe_context *context,
500 struct pipe_resource *resource,
501 unsigned level,
502 unsigned access,
503 unsigned x, unsigned y, unsigned z,
504 unsigned w, unsigned h, unsigned d,
505 struct pipe_transfer **transfer)
506 {
507 struct pipe_box box;
508 u_box_3d(x, y, z, w, h, d, &box);
509 return context->transfer_map(context,
510 resource,
511 level,
512 access,
513 &box, transfer);
514 }
515
516 static inline void
pipe_transfer_unmap(struct pipe_context * context,struct pipe_transfer * transfer)517 pipe_transfer_unmap(struct pipe_context *context,
518 struct pipe_transfer *transfer)
519 {
520 context->transfer_unmap(context, transfer);
521 }
522
523 static inline void
pipe_set_constant_buffer(struct pipe_context * pipe,enum pipe_shader_type shader,uint index,struct pipe_resource * buf)524 pipe_set_constant_buffer(struct pipe_context *pipe,
525 enum pipe_shader_type shader, uint index,
526 struct pipe_resource *buf)
527 {
528 if (buf) {
529 struct pipe_constant_buffer cb;
530 cb.buffer = buf;
531 cb.buffer_offset = 0;
532 cb.buffer_size = buf->width0;
533 cb.user_buffer = NULL;
534 pipe->set_constant_buffer(pipe, shader, index, &cb);
535 } else {
536 pipe->set_constant_buffer(pipe, shader, index, NULL);
537 }
538 }
539
540
541 /**
542 * Get the polygon offset enable/disable flag for the given polygon fill mode.
543 * \param fill_mode one of PIPE_POLYGON_MODE_POINT/LINE/FILL
544 */
545 static inline boolean
util_get_offset(const struct pipe_rasterizer_state * templ,unsigned fill_mode)546 util_get_offset(const struct pipe_rasterizer_state *templ,
547 unsigned fill_mode)
548 {
549 switch(fill_mode) {
550 case PIPE_POLYGON_MODE_POINT:
551 return templ->offset_point;
552 case PIPE_POLYGON_MODE_LINE:
553 return templ->offset_line;
554 case PIPE_POLYGON_MODE_FILL:
555 return templ->offset_tri;
556 default:
557 assert(0);
558 return FALSE;
559 }
560 }
561
562 static inline float
util_get_min_point_size(const struct pipe_rasterizer_state * state)563 util_get_min_point_size(const struct pipe_rasterizer_state *state)
564 {
565 /* The point size should be clamped to this value at the rasterizer stage.
566 */
567 return !state->point_quad_rasterization &&
568 !state->point_smooth &&
569 !state->multisample ? 1.0f : 0.0f;
570 }
571
572 static inline void
util_query_clear_result(union pipe_query_result * result,unsigned type)573 util_query_clear_result(union pipe_query_result *result, unsigned type)
574 {
575 switch (type) {
576 case PIPE_QUERY_OCCLUSION_PREDICATE:
577 case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
578 case PIPE_QUERY_SO_OVERFLOW_PREDICATE:
579 case PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE:
580 case PIPE_QUERY_GPU_FINISHED:
581 result->b = FALSE;
582 break;
583 case PIPE_QUERY_OCCLUSION_COUNTER:
584 case PIPE_QUERY_TIMESTAMP:
585 case PIPE_QUERY_TIME_ELAPSED:
586 case PIPE_QUERY_PRIMITIVES_GENERATED:
587 case PIPE_QUERY_PRIMITIVES_EMITTED:
588 result->u64 = 0;
589 break;
590 case PIPE_QUERY_SO_STATISTICS:
591 memset(&result->so_statistics, 0, sizeof(result->so_statistics));
592 break;
593 case PIPE_QUERY_TIMESTAMP_DISJOINT:
594 memset(&result->timestamp_disjoint, 0, sizeof(result->timestamp_disjoint));
595 break;
596 case PIPE_QUERY_PIPELINE_STATISTICS:
597 memset(&result->pipeline_statistics, 0, sizeof(result->pipeline_statistics));
598 break;
599 default:
600 memset(result, 0, sizeof(*result));
601 }
602 }
603
604 /** Convert PIPE_TEXTURE_x to TGSI_TEXTURE_x */
605 static inline enum tgsi_texture_type
util_pipe_tex_to_tgsi_tex(enum pipe_texture_target pipe_tex_target,unsigned nr_samples)606 util_pipe_tex_to_tgsi_tex(enum pipe_texture_target pipe_tex_target,
607 unsigned nr_samples)
608 {
609 switch (pipe_tex_target) {
610 case PIPE_BUFFER:
611 return TGSI_TEXTURE_BUFFER;
612
613 case PIPE_TEXTURE_1D:
614 assert(nr_samples <= 1);
615 return TGSI_TEXTURE_1D;
616
617 case PIPE_TEXTURE_2D:
618 return nr_samples > 1 ? TGSI_TEXTURE_2D_MSAA : TGSI_TEXTURE_2D;
619
620 case PIPE_TEXTURE_RECT:
621 assert(nr_samples <= 1);
622 return TGSI_TEXTURE_RECT;
623
624 case PIPE_TEXTURE_3D:
625 assert(nr_samples <= 1);
626 return TGSI_TEXTURE_3D;
627
628 case PIPE_TEXTURE_CUBE:
629 assert(nr_samples <= 1);
630 return TGSI_TEXTURE_CUBE;
631
632 case PIPE_TEXTURE_1D_ARRAY:
633 assert(nr_samples <= 1);
634 return TGSI_TEXTURE_1D_ARRAY;
635
636 case PIPE_TEXTURE_2D_ARRAY:
637 return nr_samples > 1 ? TGSI_TEXTURE_2D_ARRAY_MSAA :
638 TGSI_TEXTURE_2D_ARRAY;
639
640 case PIPE_TEXTURE_CUBE_ARRAY:
641 return TGSI_TEXTURE_CUBE_ARRAY;
642
643 default:
644 assert(0 && "unexpected texture target");
645 return TGSI_TEXTURE_UNKNOWN;
646 }
647 }
648
649
650 static inline void
util_copy_constant_buffer(struct pipe_constant_buffer * dst,const struct pipe_constant_buffer * src)651 util_copy_constant_buffer(struct pipe_constant_buffer *dst,
652 const struct pipe_constant_buffer *src)
653 {
654 if (src) {
655 pipe_resource_reference(&dst->buffer, src->buffer);
656 dst->buffer_offset = src->buffer_offset;
657 dst->buffer_size = src->buffer_size;
658 dst->user_buffer = src->user_buffer;
659 }
660 else {
661 pipe_resource_reference(&dst->buffer, NULL);
662 dst->buffer_offset = 0;
663 dst->buffer_size = 0;
664 dst->user_buffer = NULL;
665 }
666 }
667
668 static inline void
util_copy_shader_buffer(struct pipe_shader_buffer * dst,const struct pipe_shader_buffer * src)669 util_copy_shader_buffer(struct pipe_shader_buffer *dst,
670 const struct pipe_shader_buffer *src)
671 {
672 if (src) {
673 pipe_resource_reference(&dst->buffer, src->buffer);
674 dst->buffer_offset = src->buffer_offset;
675 dst->buffer_size = src->buffer_size;
676 }
677 else {
678 pipe_resource_reference(&dst->buffer, NULL);
679 dst->buffer_offset = 0;
680 dst->buffer_size = 0;
681 }
682 }
683
684 static inline void
util_copy_image_view(struct pipe_image_view * dst,const struct pipe_image_view * src)685 util_copy_image_view(struct pipe_image_view *dst,
686 const struct pipe_image_view *src)
687 {
688 if (src) {
689 pipe_resource_reference(&dst->resource, src->resource);
690 dst->format = src->format;
691 dst->access = src->access;
692 dst->shader_access = src->shader_access;
693 dst->u = src->u;
694 } else {
695 pipe_resource_reference(&dst->resource, NULL);
696 dst->format = PIPE_FORMAT_NONE;
697 dst->access = 0;
698 dst->shader_access = 0;
699 memset(&dst->u, 0, sizeof(dst->u));
700 }
701 }
702
703 static inline unsigned
util_max_layer(const struct pipe_resource * r,unsigned level)704 util_max_layer(const struct pipe_resource *r, unsigned level)
705 {
706 switch (r->target) {
707 case PIPE_TEXTURE_3D:
708 return u_minify(r->depth0, level) - 1;
709 case PIPE_TEXTURE_CUBE:
710 assert(r->array_size == 6);
711 /* fall-through */
712 case PIPE_TEXTURE_1D_ARRAY:
713 case PIPE_TEXTURE_2D_ARRAY:
714 case PIPE_TEXTURE_CUBE_ARRAY:
715 return r->array_size - 1;
716 default:
717 return 0;
718 }
719 }
720
721 static inline unsigned
util_num_layers(const struct pipe_resource * r,unsigned level)722 util_num_layers(const struct pipe_resource *r, unsigned level)
723 {
724 return util_max_layer(r, level) + 1;
725 }
726
727 static inline bool
util_texrange_covers_whole_level(const struct pipe_resource * tex,unsigned level,unsigned x,unsigned y,unsigned z,unsigned width,unsigned height,unsigned depth)728 util_texrange_covers_whole_level(const struct pipe_resource *tex,
729 unsigned level, unsigned x, unsigned y,
730 unsigned z, unsigned width,
731 unsigned height, unsigned depth)
732 {
733 return x == 0 && y == 0 && z == 0 &&
734 width == u_minify(tex->width0, level) &&
735 height == u_minify(tex->height0, level) &&
736 depth == util_num_layers(tex, level);
737 }
738
739 static inline bool
util_logicop_reads_dest(enum pipe_logicop op)740 util_logicop_reads_dest(enum pipe_logicop op)
741 {
742 switch (op) {
743 case PIPE_LOGICOP_NOR:
744 case PIPE_LOGICOP_AND_INVERTED:
745 case PIPE_LOGICOP_AND_REVERSE:
746 case PIPE_LOGICOP_INVERT:
747 case PIPE_LOGICOP_XOR:
748 case PIPE_LOGICOP_NAND:
749 case PIPE_LOGICOP_AND:
750 case PIPE_LOGICOP_EQUIV:
751 case PIPE_LOGICOP_NOOP:
752 case PIPE_LOGICOP_OR_INVERTED:
753 case PIPE_LOGICOP_OR_REVERSE:
754 case PIPE_LOGICOP_OR:
755 return true;
756 case PIPE_LOGICOP_CLEAR:
757 case PIPE_LOGICOP_COPY_INVERTED:
758 case PIPE_LOGICOP_COPY:
759 case PIPE_LOGICOP_SET:
760 return false;
761 }
762 unreachable("bad logicop");
763 }
764
765 static inline struct pipe_context *
pipe_create_multimedia_context(struct pipe_screen * screen)766 pipe_create_multimedia_context(struct pipe_screen *screen)
767 {
768 unsigned flags = 0;
769
770 if (!screen->get_param(screen, PIPE_CAP_GRAPHICS))
771 flags |= PIPE_CONTEXT_COMPUTE_ONLY;
772
773 return screen->context_create(screen, NULL, flags);
774 }
775
util_res_sample_count(struct pipe_resource * res)776 static inline unsigned util_res_sample_count(struct pipe_resource *res)
777 {
778 return res->nr_samples > 0 ? res->nr_samples : 1;
779 }
780
781 #ifdef __cplusplus
782 }
783 #endif
784
785 #endif /* U_INLINES_H */
786