1af69d88dSmrg/**************************************************************************
2af69d88dSmrg *
3af69d88dSmrg * Copyright 2012 Marek Olšák <maraeo@gmail.com>
4af69d88dSmrg * All Rights Reserved.
5af69d88dSmrg *
6af69d88dSmrg * Permission is hereby granted, free of charge, to any person obtaining a
7af69d88dSmrg * copy of this software and associated documentation files (the
8af69d88dSmrg * "Software"), to deal in the Software without restriction, including
9af69d88dSmrg * without limitation the rights to use, copy, modify, merge, publish,
10af69d88dSmrg * distribute, sub license, and/or sell copies of the Software, and to
11af69d88dSmrg * permit persons to whom the Software is furnished to do so, subject to
12af69d88dSmrg * the following conditions:
13af69d88dSmrg *
14af69d88dSmrg * The above copyright notice and this permission notice (including the
15af69d88dSmrg * next paragraph) shall be included in all copies or substantial portions
16af69d88dSmrg * of the Software.
17af69d88dSmrg *
18af69d88dSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19af69d88dSmrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20af69d88dSmrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21af69d88dSmrg * IN NO EVENT SHALL THE AUTHORS AND/OR THEIR SUPPLIERS BE LIABLE FOR
22af69d88dSmrg * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23af69d88dSmrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24af69d88dSmrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25af69d88dSmrg *
26af69d88dSmrg **************************************************************************/
27af69d88dSmrg
2801e04c3fSmrg#include "util/u_cpu_detect.h"
29af69d88dSmrg#include "util/u_helpers.h"
30af69d88dSmrg#include "util/u_inlines.h"
3101e04c3fSmrg#include "util/u_upload_mgr.h"
3201e04c3fSmrg#include "util/u_thread.h"
3301e04c3fSmrg#include "util/os_time.h"
3401e04c3fSmrg#include <inttypes.h>
35af69d88dSmrg
36af69d88dSmrg/**
37af69d88dSmrg * This function is used to copy an array of pipe_vertex_buffer structures,
38af69d88dSmrg * while properly referencing the pipe_vertex_buffer::buffer member.
39af69d88dSmrg *
40af69d88dSmrg * enabled_buffers is updated such that the bits corresponding to the indices
41af69d88dSmrg * of disabled buffers are set to 0 and the enabled ones are set to 1.
42af69d88dSmrg *
43af69d88dSmrg * \sa util_copy_framebuffer_state
44af69d88dSmrg */
45af69d88dSmrgvoid util_set_vertex_buffers_mask(struct pipe_vertex_buffer *dst,
46af69d88dSmrg                                  uint32_t *enabled_buffers,
47af69d88dSmrg                                  const struct pipe_vertex_buffer *src,
487ec681f3Smrg                                  unsigned start_slot, unsigned count,
497ec681f3Smrg                                  unsigned unbind_num_trailing_slots,
507ec681f3Smrg                                  bool take_ownership)
51af69d88dSmrg{
52af69d88dSmrg   unsigned i;
53af69d88dSmrg   uint32_t bitmask = 0;
54af69d88dSmrg
55af69d88dSmrg   dst += start_slot;
56af69d88dSmrg
577ec681f3Smrg   *enabled_buffers &= ~u_bit_consecutive(start_slot, count);
587ec681f3Smrg
59af69d88dSmrg   if (src) {
60af69d88dSmrg      for (i = 0; i < count; i++) {
6101e04c3fSmrg         if (src[i].buffer.resource)
62af69d88dSmrg            bitmask |= 1 << i;
6301e04c3fSmrg
6401e04c3fSmrg         pipe_vertex_buffer_unreference(&dst[i]);
6501e04c3fSmrg
667ec681f3Smrg         if (!take_ownership && !src[i].is_user_buffer)
6701e04c3fSmrg            pipe_resource_reference(&dst[i].buffer.resource, src[i].buffer.resource);
68af69d88dSmrg      }
69af69d88dSmrg
70af69d88dSmrg      /* Copy over the other members of pipe_vertex_buffer. */
71af69d88dSmrg      memcpy(dst, src, count * sizeof(struct pipe_vertex_buffer));
72af69d88dSmrg
73af69d88dSmrg      *enabled_buffers |= bitmask << start_slot;
74af69d88dSmrg   }
75af69d88dSmrg   else {
76af69d88dSmrg      /* Unreference the buffers. */
7701e04c3fSmrg      for (i = 0; i < count; i++)
7801e04c3fSmrg         pipe_vertex_buffer_unreference(&dst[i]);
79af69d88dSmrg   }
807ec681f3Smrg
817ec681f3Smrg   for (i = 0; i < unbind_num_trailing_slots; i++)
827ec681f3Smrg      pipe_vertex_buffer_unreference(&dst[count + i]);
83af69d88dSmrg}
84af69d88dSmrg
85af69d88dSmrg/**
86af69d88dSmrg * Same as util_set_vertex_buffers_mask, but it only returns the number
87af69d88dSmrg * of bound buffers.
88af69d88dSmrg */
89af69d88dSmrgvoid util_set_vertex_buffers_count(struct pipe_vertex_buffer *dst,
90af69d88dSmrg                                   unsigned *dst_count,
91af69d88dSmrg                                   const struct pipe_vertex_buffer *src,
927ec681f3Smrg                                   unsigned start_slot, unsigned count,
937ec681f3Smrg                                   unsigned unbind_num_trailing_slots,
947ec681f3Smrg                                   bool take_ownership)
95af69d88dSmrg{
9601e04c3fSmrg   unsigned i;
9701e04c3fSmrg   uint32_t enabled_buffers = 0;
9801e04c3fSmrg
9901e04c3fSmrg   for (i = 0; i < *dst_count; i++) {
10001e04c3fSmrg      if (dst[i].buffer.resource)
10101e04c3fSmrg         enabled_buffers |= (1ull << i);
10201e04c3fSmrg   }
103af69d88dSmrg
104af69d88dSmrg   util_set_vertex_buffers_mask(dst, &enabled_buffers, src, start_slot,
1057ec681f3Smrg                                count, unbind_num_trailing_slots,
1067ec681f3Smrg                                take_ownership);
107af69d88dSmrg
108af69d88dSmrg   *dst_count = util_last_bit(enabled_buffers);
109af69d88dSmrg}
11001e04c3fSmrg
1117ec681f3Smrg/**
1127ec681f3Smrg * This function is used to copy an array of pipe_shader_buffer structures,
1137ec681f3Smrg * while properly referencing the pipe_shader_buffer::buffer member.
1147ec681f3Smrg *
1157ec681f3Smrg * \sa util_set_vertex_buffer_mask
1167ec681f3Smrg */
1177ec681f3Smrgvoid util_set_shader_buffers_mask(struct pipe_shader_buffer *dst,
1187ec681f3Smrg                                  uint32_t *enabled_buffers,
1197ec681f3Smrg                                  const struct pipe_shader_buffer *src,
1207ec681f3Smrg                                  unsigned start_slot, unsigned count)
1217ec681f3Smrg{
1227ec681f3Smrg   unsigned i;
1237ec681f3Smrg
1247ec681f3Smrg   dst += start_slot;
1257ec681f3Smrg
1267ec681f3Smrg   if (src) {
1277ec681f3Smrg      for (i = 0; i < count; i++) {
1287ec681f3Smrg         pipe_resource_reference(&dst[i].buffer, src[i].buffer);
1297ec681f3Smrg
1307ec681f3Smrg         if (src[i].buffer)
1317ec681f3Smrg            *enabled_buffers |= (1ull << (start_slot + i));
1327ec681f3Smrg         else
1337ec681f3Smrg            *enabled_buffers &= ~(1ull << (start_slot + i));
1347ec681f3Smrg      }
1357ec681f3Smrg
1367ec681f3Smrg      /* Copy over the other members of pipe_shader_buffer. */
1377ec681f3Smrg      memcpy(dst, src, count * sizeof(struct pipe_shader_buffer));
1387ec681f3Smrg   }
1397ec681f3Smrg   else {
1407ec681f3Smrg      /* Unreference the buffers. */
1417ec681f3Smrg      for (i = 0; i < count; i++)
1427ec681f3Smrg         pipe_resource_reference(&dst[i].buffer, NULL);
1437ec681f3Smrg
1447ec681f3Smrg      *enabled_buffers &= ~(((1ull << count) - 1) << start_slot);
1457ec681f3Smrg   }
1467ec681f3Smrg}
1477ec681f3Smrg
14801e04c3fSmrg/**
14901e04c3fSmrg * Given a user index buffer, save the structure to "saved", and upload it.
15001e04c3fSmrg */
15101e04c3fSmrgbool
15201e04c3fSmrgutil_upload_index_buffer(struct pipe_context *pipe,
15301e04c3fSmrg                         const struct pipe_draw_info *info,
1547ec681f3Smrg                         const struct pipe_draw_start_count_bias *draw,
15501e04c3fSmrg                         struct pipe_resource **out_buffer,
1567ec681f3Smrg                         unsigned *out_offset, unsigned alignment)
15701e04c3fSmrg{
1587ec681f3Smrg   unsigned start_offset = draw->start * info->index_size;
15901e04c3fSmrg
16001e04c3fSmrg   u_upload_data(pipe->stream_uploader, start_offset,
1617ec681f3Smrg                 draw->count * info->index_size, alignment,
16201e04c3fSmrg                 (char*)info->index.user + start_offset,
16301e04c3fSmrg                 out_offset, out_buffer);
16401e04c3fSmrg   u_upload_unmap(pipe->stream_uploader);
16501e04c3fSmrg   *out_offset -= start_offset;
16601e04c3fSmrg   return *out_buffer != NULL;
16701e04c3fSmrg}
16801e04c3fSmrg
16901e04c3fSmrg/**
1707ec681f3Smrg * Lower each UINT64 vertex element to 1 or 2 UINT32 vertex elements.
1717ec681f3Smrg * 3 and 4 component formats are expanded into 2 slots.
17201e04c3fSmrg *
1737ec681f3Smrg * @param velems        Original vertex elements, will be updated to contain
1747ec681f3Smrg *                      the lowered vertex elements.
1757ec681f3Smrg * @param velem_count   Original count, will be updated to contain the count
1767ec681f3Smrg *                      after lowering.
1777ec681f3Smrg * @param tmp           Temporary array of PIPE_MAX_ATTRIBS vertex elements.
17801e04c3fSmrg */
17901e04c3fSmrgvoid
1807ec681f3Smrgutil_lower_uint64_vertex_elements(const struct pipe_vertex_element **velems,
1817ec681f3Smrg                                  unsigned *velem_count,
1827ec681f3Smrg                                  struct pipe_vertex_element tmp[PIPE_MAX_ATTRIBS])
18301e04c3fSmrg{
1847ec681f3Smrg   const struct pipe_vertex_element *input = *velems;
1857ec681f3Smrg   unsigned count = *velem_count;
1867ec681f3Smrg   bool has_64bit = false;
18701e04c3fSmrg
1887ec681f3Smrg   for (unsigned i = 0; i < count; i++) {
1897ec681f3Smrg      has_64bit |= input[i].src_format >= PIPE_FORMAT_R64_UINT &&
1907ec681f3Smrg                   input[i].src_format <= PIPE_FORMAT_R64G64B64A64_UINT;
1917ec681f3Smrg   }
1927ec681f3Smrg
1937ec681f3Smrg   /* Return the original vertex elements if there is nothing to do. */
1947ec681f3Smrg   if (!has_64bit)
1957ec681f3Smrg      return;
19601e04c3fSmrg
1977ec681f3Smrg   /* Lower 64_UINT to 32_UINT. */
1987ec681f3Smrg   unsigned new_count = 0;
1997ec681f3Smrg
2007ec681f3Smrg   for (unsigned i = 0; i < count; i++) {
2017ec681f3Smrg      enum pipe_format format = input[i].src_format;
2027ec681f3Smrg
2037ec681f3Smrg      /* If the shader input is dvec2 or smaller, reduce the number of
2047ec681f3Smrg       * components to 2 at most. If the shader input is dvec3 or larger,
2057ec681f3Smrg       * expand the number of components to 3 at least. If the 3rd component
2067ec681f3Smrg       * is out of bounds, the hardware shouldn't skip loading the first
2077ec681f3Smrg       * 2 components.
2087ec681f3Smrg       */
2097ec681f3Smrg      if (format >= PIPE_FORMAT_R64_UINT &&
2107ec681f3Smrg          format <= PIPE_FORMAT_R64G64B64A64_UINT) {
2117ec681f3Smrg         if (input[i].dual_slot)
2127ec681f3Smrg            format = MAX2(format, PIPE_FORMAT_R64G64B64_UINT);
2137ec681f3Smrg         else
2147ec681f3Smrg            format = MIN2(format, PIPE_FORMAT_R64G64_UINT);
2157ec681f3Smrg      }
21601e04c3fSmrg
2177ec681f3Smrg      switch (format) {
2187ec681f3Smrg      case PIPE_FORMAT_R64_UINT:
2197ec681f3Smrg         tmp[new_count] = input[i];
2207ec681f3Smrg         tmp[new_count].src_format = PIPE_FORMAT_R32G32_UINT;
2217ec681f3Smrg         new_count++;
2227ec681f3Smrg         break;
2237ec681f3Smrg
2247ec681f3Smrg      case PIPE_FORMAT_R64G64_UINT:
2257ec681f3Smrg         tmp[new_count] = input[i];
2267ec681f3Smrg         tmp[new_count].src_format = PIPE_FORMAT_R32G32B32A32_UINT;
2277ec681f3Smrg         new_count++;
2287ec681f3Smrg         break;
2297ec681f3Smrg
2307ec681f3Smrg      case PIPE_FORMAT_R64G64B64_UINT:
2317ec681f3Smrg      case PIPE_FORMAT_R64G64B64A64_UINT:
2327ec681f3Smrg         assert(new_count + 2 <= PIPE_MAX_ATTRIBS);
2337ec681f3Smrg         tmp[new_count] = tmp[new_count + 1] = input[i];
2347ec681f3Smrg         tmp[new_count].src_format = PIPE_FORMAT_R32G32B32A32_UINT;
2357ec681f3Smrg         tmp[new_count + 1].src_format =
2367ec681f3Smrg            format == PIPE_FORMAT_R64G64B64_UINT ?
2377ec681f3Smrg                  PIPE_FORMAT_R32G32_UINT :
2387ec681f3Smrg                  PIPE_FORMAT_R32G32B32A32_UINT;
2397ec681f3Smrg         tmp[new_count + 1].src_offset += 16;
2407ec681f3Smrg         new_count += 2;
2417ec681f3Smrg         break;
2427ec681f3Smrg
2437ec681f3Smrg      default:
2447ec681f3Smrg         tmp[new_count++] = input[i];
2457ec681f3Smrg         break;
2467ec681f3Smrg      }
24701e04c3fSmrg   }
24801e04c3fSmrg
2497ec681f3Smrg   *velem_count = new_count;
2507ec681f3Smrg   *velems = tmp;
25101e04c3fSmrg}
25201e04c3fSmrg
25301e04c3fSmrg/* This is a helper for hardware bring-up. Don't remove. */
25401e04c3fSmrgstruct pipe_query *
25501e04c3fSmrgutil_begin_pipestat_query(struct pipe_context *ctx)
25601e04c3fSmrg{
25701e04c3fSmrg   struct pipe_query *q =
25801e04c3fSmrg      ctx->create_query(ctx, PIPE_QUERY_PIPELINE_STATISTICS, 0);
25901e04c3fSmrg   if (!q)
26001e04c3fSmrg      return NULL;
26101e04c3fSmrg
26201e04c3fSmrg   ctx->begin_query(ctx, q);
26301e04c3fSmrg   return q;
26401e04c3fSmrg}
26501e04c3fSmrg
26601e04c3fSmrg/* This is a helper for hardware bring-up. Don't remove. */
26701e04c3fSmrgvoid
26801e04c3fSmrgutil_end_pipestat_query(struct pipe_context *ctx, struct pipe_query *q,
26901e04c3fSmrg                        FILE *f)
27001e04c3fSmrg{
27101e04c3fSmrg   static unsigned counter;
27201e04c3fSmrg   struct pipe_query_data_pipeline_statistics stats;
27301e04c3fSmrg
27401e04c3fSmrg   ctx->end_query(ctx, q);
27501e04c3fSmrg   ctx->get_query_result(ctx, q, true, (void*)&stats);
27601e04c3fSmrg   ctx->destroy_query(ctx, q);
27701e04c3fSmrg
27801e04c3fSmrg   fprintf(f,
27901e04c3fSmrg           "Draw call %u:\n"
28001e04c3fSmrg           "    ia_vertices    = %"PRIu64"\n"
28101e04c3fSmrg           "    ia_primitives  = %"PRIu64"\n"
28201e04c3fSmrg           "    vs_invocations = %"PRIu64"\n"
28301e04c3fSmrg           "    gs_invocations = %"PRIu64"\n"
28401e04c3fSmrg           "    gs_primitives  = %"PRIu64"\n"
28501e04c3fSmrg           "    c_invocations  = %"PRIu64"\n"
28601e04c3fSmrg           "    c_primitives   = %"PRIu64"\n"
28701e04c3fSmrg           "    ps_invocations = %"PRIu64"\n"
28801e04c3fSmrg           "    hs_invocations = %"PRIu64"\n"
28901e04c3fSmrg           "    ds_invocations = %"PRIu64"\n"
29001e04c3fSmrg           "    cs_invocations = %"PRIu64"\n",
2917ec681f3Smrg           (unsigned)p_atomic_inc_return(&counter),
29201e04c3fSmrg           stats.ia_vertices,
29301e04c3fSmrg           stats.ia_primitives,
29401e04c3fSmrg           stats.vs_invocations,
29501e04c3fSmrg           stats.gs_invocations,
29601e04c3fSmrg           stats.gs_primitives,
29701e04c3fSmrg           stats.c_invocations,
29801e04c3fSmrg           stats.c_primitives,
29901e04c3fSmrg           stats.ps_invocations,
30001e04c3fSmrg           stats.hs_invocations,
30101e04c3fSmrg           stats.ds_invocations,
30201e04c3fSmrg           stats.cs_invocations);
30301e04c3fSmrg}
30401e04c3fSmrg
3057ec681f3Smrg/* This is a helper for profiling. Don't remove. */
3067ec681f3Smrgstruct pipe_query *
3077ec681f3Smrgutil_begin_time_query(struct pipe_context *ctx)
3087ec681f3Smrg{
3097ec681f3Smrg   struct pipe_query *q =
3107ec681f3Smrg      ctx->create_query(ctx, PIPE_QUERY_TIME_ELAPSED, 0);
3117ec681f3Smrg   if (!q)
3127ec681f3Smrg      return NULL;
3137ec681f3Smrg
3147ec681f3Smrg   ctx->begin_query(ctx, q);
3157ec681f3Smrg   return q;
3167ec681f3Smrg}
3177ec681f3Smrg
3187ec681f3Smrg/* This is a helper for profiling. Don't remove. */
3197ec681f3Smrgvoid
3207ec681f3Smrgutil_end_time_query(struct pipe_context *ctx, struct pipe_query *q, FILE *f,
3217ec681f3Smrg                    const char *name)
3227ec681f3Smrg{
3237ec681f3Smrg   union pipe_query_result result;
3247ec681f3Smrg
3257ec681f3Smrg   ctx->end_query(ctx, q);
3267ec681f3Smrg   ctx->get_query_result(ctx, q, true, &result);
3277ec681f3Smrg   ctx->destroy_query(ctx, q);
3287ec681f3Smrg
3297ec681f3Smrg   fprintf(f, "Time elapsed: %s - %"PRIu64".%u us\n", name, result.u64 / 1000, (unsigned)(result.u64 % 1000) / 100);
3307ec681f3Smrg}
3317ec681f3Smrg
33201e04c3fSmrg/* This is a helper for hardware bring-up. Don't remove. */
33301e04c3fSmrgvoid
33401e04c3fSmrgutil_wait_for_idle(struct pipe_context *ctx)
33501e04c3fSmrg{
33601e04c3fSmrg   struct pipe_fence_handle *fence = NULL;
33701e04c3fSmrg
33801e04c3fSmrg   ctx->flush(ctx, &fence, 0);
33901e04c3fSmrg   ctx->screen->fence_finish(ctx->screen, NULL, fence, PIPE_TIMEOUT_INFINITE);
34001e04c3fSmrg}
34101e04c3fSmrg
34201e04c3fSmrgvoid
34301e04c3fSmrgutil_throttle_init(struct util_throttle *t, uint64_t max_mem_usage)
34401e04c3fSmrg{
34501e04c3fSmrg   t->max_mem_usage = max_mem_usage;
34601e04c3fSmrg}
34701e04c3fSmrg
34801e04c3fSmrgvoid
34901e04c3fSmrgutil_throttle_deinit(struct pipe_screen *screen, struct util_throttle *t)
35001e04c3fSmrg{
35101e04c3fSmrg   for (unsigned i = 0; i < ARRAY_SIZE(t->ring); i++)
35201e04c3fSmrg      screen->fence_reference(screen, &t->ring[i].fence, NULL);
35301e04c3fSmrg}
35401e04c3fSmrg
35501e04c3fSmrgstatic uint64_t
35601e04c3fSmrgutil_get_throttle_total_memory_usage(struct util_throttle *t)
35701e04c3fSmrg{
35801e04c3fSmrg   uint64_t total_usage = 0;
35901e04c3fSmrg
36001e04c3fSmrg   for (unsigned i = 0; i < ARRAY_SIZE(t->ring); i++)
36101e04c3fSmrg      total_usage += t->ring[i].mem_usage;
36201e04c3fSmrg   return total_usage;
36301e04c3fSmrg}
36401e04c3fSmrg
36501e04c3fSmrgstatic void util_dump_throttle_ring(struct util_throttle *t)
36601e04c3fSmrg{
36701e04c3fSmrg   printf("Throttle:\n");
36801e04c3fSmrg   for (unsigned i = 0; i < ARRAY_SIZE(t->ring); i++) {
36901e04c3fSmrg      printf("  ring[%u]: fence = %s, mem_usage = %"PRIu64"%s%s\n",
37001e04c3fSmrg             i, t->ring[i].fence ? "yes" : " no",
37101e04c3fSmrg             t->ring[i].mem_usage,
37201e04c3fSmrg             t->flush_index == i ? " [flush]" : "",
37301e04c3fSmrg             t->wait_index == i ? " [wait]" : "");
37401e04c3fSmrg   }
37501e04c3fSmrg}
37601e04c3fSmrg
37701e04c3fSmrg/**
37801e04c3fSmrg * Notify util_throttle that the next operation allocates memory.
37901e04c3fSmrg * util_throttle tracks memory usage and waits for fences until its tracked
38001e04c3fSmrg * memory usage decreases.
38101e04c3fSmrg *
38201e04c3fSmrg * Example:
38301e04c3fSmrg *   util_throttle_memory_usage(..., w*h*d*Bpp);
38401e04c3fSmrg *   TexSubImage(..., w, h, d, ...);
38501e04c3fSmrg *
38601e04c3fSmrg * This means that TexSubImage can't allocate more memory its maximum limit
38701e04c3fSmrg * set during initialization.
38801e04c3fSmrg */
38901e04c3fSmrgvoid
39001e04c3fSmrgutil_throttle_memory_usage(struct pipe_context *pipe,
39101e04c3fSmrg                           struct util_throttle *t, uint64_t memory_size)
39201e04c3fSmrg{
39301e04c3fSmrg   (void)util_dump_throttle_ring; /* silence warning */
39401e04c3fSmrg
39501e04c3fSmrg   if (!t->max_mem_usage)
39601e04c3fSmrg      return;
39701e04c3fSmrg
39801e04c3fSmrg   struct pipe_screen *screen = pipe->screen;
39901e04c3fSmrg   struct pipe_fence_handle **fence = NULL;
40001e04c3fSmrg   unsigned ring_size = ARRAY_SIZE(t->ring);
40101e04c3fSmrg   uint64_t total = util_get_throttle_total_memory_usage(t);
40201e04c3fSmrg
40301e04c3fSmrg   /* If there is not enough memory, walk the list of fences and find
40401e04c3fSmrg    * the latest one that we need to wait for.
40501e04c3fSmrg    */
40601e04c3fSmrg   while (t->wait_index != t->flush_index &&
40701e04c3fSmrg          total && total + memory_size > t->max_mem_usage) {
40801e04c3fSmrg      assert(t->ring[t->wait_index].fence);
40901e04c3fSmrg
41001e04c3fSmrg      /* Release an older fence if we need to wait for a newer one. */
41101e04c3fSmrg      if (fence)
41201e04c3fSmrg         screen->fence_reference(screen, fence, NULL);
41301e04c3fSmrg
41401e04c3fSmrg      fence = &t->ring[t->wait_index].fence;
41501e04c3fSmrg      t->ring[t->wait_index].mem_usage = 0;
41601e04c3fSmrg      t->wait_index = (t->wait_index + 1) % ring_size;
41701e04c3fSmrg
41801e04c3fSmrg      total = util_get_throttle_total_memory_usage(t);
41901e04c3fSmrg   }
42001e04c3fSmrg
42101e04c3fSmrg   /* Wait for the fence to decrease memory usage. */
42201e04c3fSmrg   if (fence) {
42301e04c3fSmrg      screen->fence_finish(screen, pipe, *fence, PIPE_TIMEOUT_INFINITE);
42401e04c3fSmrg      screen->fence_reference(screen, fence, NULL);
42501e04c3fSmrg   }
42601e04c3fSmrg
42701e04c3fSmrg   /* Flush and get a fence if we've exhausted memory usage for the current
42801e04c3fSmrg    * slot.
42901e04c3fSmrg    */
43001e04c3fSmrg   if (t->ring[t->flush_index].mem_usage &&
43101e04c3fSmrg       t->ring[t->flush_index].mem_usage + memory_size >
43201e04c3fSmrg       t->max_mem_usage / (ring_size / 2)) {
43301e04c3fSmrg      struct pipe_fence_handle **fence =
43401e04c3fSmrg         &t->ring[t->flush_index].fence;
43501e04c3fSmrg
43601e04c3fSmrg      /* Expect that the current flush slot doesn't have a fence yet. */
43701e04c3fSmrg      assert(!*fence);
43801e04c3fSmrg
43901e04c3fSmrg      pipe->flush(pipe, fence, PIPE_FLUSH_ASYNC);
44001e04c3fSmrg      t->flush_index = (t->flush_index + 1) % ring_size;
44101e04c3fSmrg
44201e04c3fSmrg      /* Vacate the next slot if it's occupied. This should be rare. */
44301e04c3fSmrg      if (t->flush_index == t->wait_index) {
44401e04c3fSmrg         struct pipe_fence_handle **fence =
44501e04c3fSmrg            &t->ring[t->wait_index].fence;
44601e04c3fSmrg
44701e04c3fSmrg         t->ring[t->wait_index].mem_usage = 0;
44801e04c3fSmrg         t->wait_index = (t->wait_index + 1) % ring_size;
44901e04c3fSmrg
45001e04c3fSmrg         assert(*fence);
45101e04c3fSmrg         screen->fence_finish(screen, pipe, *fence, PIPE_TIMEOUT_INFINITE);
45201e04c3fSmrg         screen->fence_reference(screen, fence, NULL);
45301e04c3fSmrg      }
45401e04c3fSmrg
45501e04c3fSmrg      assert(!t->ring[t->flush_index].mem_usage);
45601e04c3fSmrg      assert(!t->ring[t->flush_index].fence);
45701e04c3fSmrg   }
45801e04c3fSmrg
45901e04c3fSmrg   t->ring[t->flush_index].mem_usage += memory_size;
46001e04c3fSmrg}
4617ec681f3Smrg
4627ec681f3Smrgbool
4637ec681f3Smrgutil_lower_clearsize_to_dword(const void *clearValue, int *clearValueSize, uint32_t *clamped)
4647ec681f3Smrg{
4657ec681f3Smrg   /* Reduce a large clear value size if possible. */
4667ec681f3Smrg   if (*clearValueSize > 4) {
4677ec681f3Smrg      bool clear_dword_duplicated = true;
4687ec681f3Smrg      const uint32_t *clear_value = clearValue;
4697ec681f3Smrg
4707ec681f3Smrg      /* See if we can lower large fills to dword fills. */
4717ec681f3Smrg      for (unsigned i = 1; i < *clearValueSize / 4; i++) {
4727ec681f3Smrg         if (clear_value[0] != clear_value[i]) {
4737ec681f3Smrg            clear_dword_duplicated = false;
4747ec681f3Smrg            break;
4757ec681f3Smrg         }
4767ec681f3Smrg      }
4777ec681f3Smrg      if (clear_dword_duplicated) {
4787ec681f3Smrg         *clamped = *clear_value;
4797ec681f3Smrg         *clearValueSize = 4;
4807ec681f3Smrg      }
4817ec681f3Smrg      return clear_dword_duplicated;
4827ec681f3Smrg   }
4837ec681f3Smrg
4847ec681f3Smrg   /* Expand a small clear value size. */
4857ec681f3Smrg   if (*clearValueSize <= 2) {
4867ec681f3Smrg      if (*clearValueSize == 1) {
4877ec681f3Smrg         *clamped = *(uint8_t *)clearValue;
4887ec681f3Smrg         *clamped |=
4897ec681f3Smrg            (*clamped << 8) | (*clamped << 16) | (*clamped << 24);
4907ec681f3Smrg      } else {
4917ec681f3Smrg         *clamped = *(uint16_t *)clearValue;
4927ec681f3Smrg         *clamped |= *clamped << 16;
4937ec681f3Smrg      }
4947ec681f3Smrg      *clearValueSize = 4;
4957ec681f3Smrg      return true;
4967ec681f3Smrg   }
4977ec681f3Smrg   return false;
4987ec681f3Smrg}
4997ec681f3Smrg
5007ec681f3Smrgvoid
5017ec681f3Smrgutil_init_pipe_vertex_state(struct pipe_screen *screen,
5027ec681f3Smrg                            struct pipe_vertex_buffer *buffer,
5037ec681f3Smrg                            const struct pipe_vertex_element *elements,
5047ec681f3Smrg                            unsigned num_elements,
5057ec681f3Smrg                            struct pipe_resource *indexbuf,
5067ec681f3Smrg                            uint32_t full_velem_mask,
5077ec681f3Smrg                            struct pipe_vertex_state *state)
5087ec681f3Smrg{
5097ec681f3Smrg   assert(num_elements == util_bitcount(full_velem_mask));
5107ec681f3Smrg
5117ec681f3Smrg   pipe_reference_init(&state->reference, 1);
5127ec681f3Smrg   state->screen = screen;
5137ec681f3Smrg
5147ec681f3Smrg   pipe_vertex_buffer_reference(&state->input.vbuffer, buffer);
5157ec681f3Smrg   pipe_resource_reference(&state->input.indexbuf, indexbuf);
5167ec681f3Smrg   state->input.num_elements = num_elements;
5177ec681f3Smrg   for (unsigned i = 0; i < num_elements; i++)
5187ec681f3Smrg      state->input.elements[i] = elements[i];
5197ec681f3Smrg   state->input.full_velem_mask = full_velem_mask;
5207ec681f3Smrg}
521