1bf215546Sopenharmony_ci/**************************************************************************
2bf215546Sopenharmony_ci *
3bf215546Sopenharmony_ci * Copyright 2007 VMware, Inc.
4bf215546Sopenharmony_ci * All Rights Reserved.
5bf215546Sopenharmony_ci *
6bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
7bf215546Sopenharmony_ci * copy of this software and associated documentation files (the
8bf215546Sopenharmony_ci * "Software"), to deal in the Software without restriction, including
9bf215546Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish,
10bf215546Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to
11bf215546Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to
12bf215546Sopenharmony_ci * the following conditions:
13bf215546Sopenharmony_ci *
14bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the
15bf215546Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions
16bf215546Sopenharmony_ci * of the Software.
17bf215546Sopenharmony_ci *
18bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19bf215546Sopenharmony_ci * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20bf215546Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21bf215546Sopenharmony_ci * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
22bf215546Sopenharmony_ci * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23bf215546Sopenharmony_ci * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24bf215546Sopenharmony_ci * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25bf215546Sopenharmony_ci *
26bf215546Sopenharmony_ci **************************************************************************/
27bf215546Sopenharmony_ci
28bf215546Sopenharmony_ci/*
29bf215546Sopenharmony_ci * This file implements the st_draw_vbo() function which is called from
30bf215546Sopenharmony_ci * Mesa's VBO module.  All point/line/triangle rendering is done through
31bf215546Sopenharmony_ci * this function whether the user called glBegin/End, glDrawArrays,
32bf215546Sopenharmony_ci * glDrawElements, glEvalMesh, or glCalList, etc.
33bf215546Sopenharmony_ci *
34bf215546Sopenharmony_ci * Authors:
35bf215546Sopenharmony_ci *   Keith Whitwell <keithw@vmware.com>
36bf215546Sopenharmony_ci */
37bf215546Sopenharmony_ci
38bf215546Sopenharmony_ci
39bf215546Sopenharmony_ci#include "main/errors.h"
40bf215546Sopenharmony_ci
41bf215546Sopenharmony_ci#include "main/image.h"
42bf215546Sopenharmony_ci#include "main/bufferobj.h"
43bf215546Sopenharmony_ci#include "main/macros.h"
44bf215546Sopenharmony_ci#include "main/varray.h"
45bf215546Sopenharmony_ci
46bf215546Sopenharmony_ci#include "compiler/glsl/ir_uniform.h"
47bf215546Sopenharmony_ci
48bf215546Sopenharmony_ci#include "vbo/vbo.h"
49bf215546Sopenharmony_ci
50bf215546Sopenharmony_ci#include "st_context.h"
51bf215546Sopenharmony_ci#include "st_atom.h"
52bf215546Sopenharmony_ci#include "st_cb_bitmap.h"
53bf215546Sopenharmony_ci#include "st_debug.h"
54bf215546Sopenharmony_ci#include "st_draw.h"
55bf215546Sopenharmony_ci#include "st_program.h"
56bf215546Sopenharmony_ci#include "st_util.h"
57bf215546Sopenharmony_ci
58bf215546Sopenharmony_ci#include "pipe/p_context.h"
59bf215546Sopenharmony_ci#include "pipe/p_defines.h"
60bf215546Sopenharmony_ci#include "util/u_cpu_detect.h"
61bf215546Sopenharmony_ci#include "util/u_inlines.h"
62bf215546Sopenharmony_ci#include "util/format/u_format.h"
63bf215546Sopenharmony_ci#include "util/u_prim.h"
64bf215546Sopenharmony_ci#include "util/u_draw.h"
65bf215546Sopenharmony_ci#include "util/u_upload_mgr.h"
66bf215546Sopenharmony_ci#include "util/u_threaded_context.h"
67bf215546Sopenharmony_ci#include "draw/draw_context.h"
68bf215546Sopenharmony_ci#include "cso_cache/cso_context.h"
69bf215546Sopenharmony_ci
70bf215546Sopenharmony_ci
71bf215546Sopenharmony_ci/**
72bf215546Sopenharmony_ci * Translate OpenGL primtive type (GL_POINTS, GL_TRIANGLE_STRIP, etc) to
73bf215546Sopenharmony_ci * the corresponding Gallium type.
74bf215546Sopenharmony_ci */
75bf215546Sopenharmony_cistatic unsigned
76bf215546Sopenharmony_citranslate_prim(const struct gl_context *ctx, unsigned prim)
77bf215546Sopenharmony_ci{
78bf215546Sopenharmony_ci   /* GL prims should match Gallium prims, spot-check a few */
79bf215546Sopenharmony_ci   STATIC_ASSERT(GL_POINTS == PIPE_PRIM_POINTS);
80bf215546Sopenharmony_ci   STATIC_ASSERT(GL_QUADS == PIPE_PRIM_QUADS);
81bf215546Sopenharmony_ci   STATIC_ASSERT(GL_TRIANGLE_STRIP_ADJACENCY == PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY);
82bf215546Sopenharmony_ci   STATIC_ASSERT(GL_PATCHES == PIPE_PRIM_PATCHES);
83bf215546Sopenharmony_ci
84bf215546Sopenharmony_ci   return prim;
85bf215546Sopenharmony_ci}
86bf215546Sopenharmony_ci
87bf215546Sopenharmony_cistatic inline void
88bf215546Sopenharmony_ciprepare_draw(struct st_context *st, struct gl_context *ctx, uint64_t state_mask,
89bf215546Sopenharmony_ci             enum st_pipeline pipeline)
90bf215546Sopenharmony_ci{
91bf215546Sopenharmony_ci   /* Mesa core state should have been validated already */
92bf215546Sopenharmony_ci   assert(ctx->NewState == 0x0);
93bf215546Sopenharmony_ci
94bf215546Sopenharmony_ci   if (unlikely(!st->bitmap.cache.empty))
95bf215546Sopenharmony_ci      st_flush_bitmap_cache(st);
96bf215546Sopenharmony_ci
97bf215546Sopenharmony_ci   st_invalidate_readpix_cache(st);
98bf215546Sopenharmony_ci
99bf215546Sopenharmony_ci   /* Validate state. */
100bf215546Sopenharmony_ci   if ((st->dirty | ctx->NewDriverState) & st->active_states & state_mask ||
101bf215546Sopenharmony_ci       st->gfx_shaders_may_be_dirty) {
102bf215546Sopenharmony_ci      st_validate_state(st, pipeline);
103bf215546Sopenharmony_ci   }
104bf215546Sopenharmony_ci
105bf215546Sopenharmony_ci   /* Pin threads regularly to the same Zen CCX that the main thread is
106bf215546Sopenharmony_ci    * running on. The main thread can move between CCXs.
107bf215546Sopenharmony_ci    */
108bf215546Sopenharmony_ci   if (unlikely(st->pin_thread_counter != ST_L3_PINNING_DISABLED &&
109bf215546Sopenharmony_ci                /* no glthread */
110bf215546Sopenharmony_ci                !ctx->GLThread.enabled &&
111bf215546Sopenharmony_ci                /* do it occasionally */
112bf215546Sopenharmony_ci                ++st->pin_thread_counter % 512 == 0)) {
113bf215546Sopenharmony_ci      st->pin_thread_counter = 0;
114bf215546Sopenharmony_ci
115bf215546Sopenharmony_ci      int cpu = util_get_current_cpu();
116bf215546Sopenharmony_ci      if (cpu >= 0) {
117bf215546Sopenharmony_ci         struct pipe_context *pipe = st->pipe;
118bf215546Sopenharmony_ci         uint16_t L3_cache = util_get_cpu_caps()->cpu_to_L3[cpu];
119bf215546Sopenharmony_ci
120bf215546Sopenharmony_ci         if (L3_cache != U_CPU_INVALID_L3) {
121bf215546Sopenharmony_ci            pipe->set_context_param(pipe,
122bf215546Sopenharmony_ci                                    PIPE_CONTEXT_PARAM_PIN_THREADS_TO_L3_CACHE,
123bf215546Sopenharmony_ci                                    L3_cache);
124bf215546Sopenharmony_ci         }
125bf215546Sopenharmony_ci      }
126bf215546Sopenharmony_ci   }
127bf215546Sopenharmony_ci}
128bf215546Sopenharmony_ci
129bf215546Sopenharmony_cistatic bool ALWAYS_INLINE
130bf215546Sopenharmony_ciprepare_indexed_draw(/* pass both st and ctx to reduce dereferences */
131bf215546Sopenharmony_ci                     struct st_context *st,
132bf215546Sopenharmony_ci                     struct gl_context *ctx,
133bf215546Sopenharmony_ci                     struct pipe_draw_info *info,
134bf215546Sopenharmony_ci                     const struct pipe_draw_start_count_bias *draws,
135bf215546Sopenharmony_ci                     unsigned num_draws)
136bf215546Sopenharmony_ci{
137bf215546Sopenharmony_ci   if (info->index_size) {
138bf215546Sopenharmony_ci      /* Get index bounds for user buffers. */
139bf215546Sopenharmony_ci      if (!info->index_bounds_valid &&
140bf215546Sopenharmony_ci          st->draw_needs_minmax_index) {
141bf215546Sopenharmony_ci         /* Return if this fails, which means all draws have count == 0. */
142bf215546Sopenharmony_ci         if (!vbo_get_minmax_indices_gallium(ctx, info, draws, num_draws))
143bf215546Sopenharmony_ci            return false;
144bf215546Sopenharmony_ci
145bf215546Sopenharmony_ci         info->index_bounds_valid = true;
146bf215546Sopenharmony_ci      }
147bf215546Sopenharmony_ci
148bf215546Sopenharmony_ci      if (!info->has_user_indices) {
149bf215546Sopenharmony_ci         if (st->pipe->draw_vbo == tc_draw_vbo) {
150bf215546Sopenharmony_ci            /* Fast path for u_threaded_context. This eliminates the atomic
151bf215546Sopenharmony_ci             * increment for the index buffer refcount when adding it into
152bf215546Sopenharmony_ci             * the threaded batch buffer.
153bf215546Sopenharmony_ci             */
154bf215546Sopenharmony_ci            info->index.resource =
155bf215546Sopenharmony_ci               _mesa_get_bufferobj_reference(ctx, info->index.gl_bo);
156bf215546Sopenharmony_ci            info->take_index_buffer_ownership = true;
157bf215546Sopenharmony_ci         } else {
158bf215546Sopenharmony_ci            info->index.resource = info->index.gl_bo->buffer;
159bf215546Sopenharmony_ci         }
160bf215546Sopenharmony_ci
161bf215546Sopenharmony_ci         /* Return if the bound element array buffer doesn't have any backing
162bf215546Sopenharmony_ci          * storage. (nothing to do)
163bf215546Sopenharmony_ci          */
164bf215546Sopenharmony_ci         if (unlikely(!info->index.resource))
165bf215546Sopenharmony_ci            return false;
166bf215546Sopenharmony_ci      }
167bf215546Sopenharmony_ci   }
168bf215546Sopenharmony_ci   return true;
169bf215546Sopenharmony_ci}
170bf215546Sopenharmony_ci
171bf215546Sopenharmony_cistatic void
172bf215546Sopenharmony_cist_draw_gallium(struct gl_context *ctx,
173bf215546Sopenharmony_ci                struct pipe_draw_info *info,
174bf215546Sopenharmony_ci                unsigned drawid_offset,
175bf215546Sopenharmony_ci                const struct pipe_draw_start_count_bias *draws,
176bf215546Sopenharmony_ci                unsigned num_draws)
177bf215546Sopenharmony_ci{
178bf215546Sopenharmony_ci   struct st_context *st = st_context(ctx);
179bf215546Sopenharmony_ci
180bf215546Sopenharmony_ci   prepare_draw(st, ctx, ST_PIPELINE_RENDER_STATE_MASK, ST_PIPELINE_RENDER);
181bf215546Sopenharmony_ci
182bf215546Sopenharmony_ci   if (!prepare_indexed_draw(st, ctx, info, draws, num_draws))
183bf215546Sopenharmony_ci      return;
184bf215546Sopenharmony_ci
185bf215546Sopenharmony_ci   cso_multi_draw(st->cso_context, info, drawid_offset, draws, num_draws);
186bf215546Sopenharmony_ci}
187bf215546Sopenharmony_ci
188bf215546Sopenharmony_cistatic void
189bf215546Sopenharmony_cist_draw_gallium_multimode(struct gl_context *ctx,
190bf215546Sopenharmony_ci                          struct pipe_draw_info *info,
191bf215546Sopenharmony_ci                          const struct pipe_draw_start_count_bias *draws,
192bf215546Sopenharmony_ci                          const unsigned char *mode,
193bf215546Sopenharmony_ci                          unsigned num_draws)
194bf215546Sopenharmony_ci{
195bf215546Sopenharmony_ci   struct st_context *st = st_context(ctx);
196bf215546Sopenharmony_ci
197bf215546Sopenharmony_ci   prepare_draw(st, ctx, ST_PIPELINE_RENDER_STATE_MASK, ST_PIPELINE_RENDER);
198bf215546Sopenharmony_ci
199bf215546Sopenharmony_ci   if (!prepare_indexed_draw(st, ctx, info, draws, num_draws))
200bf215546Sopenharmony_ci      return;
201bf215546Sopenharmony_ci
202bf215546Sopenharmony_ci   unsigned i, first;
203bf215546Sopenharmony_ci   struct cso_context *cso = st->cso_context;
204bf215546Sopenharmony_ci
205bf215546Sopenharmony_ci   /* Find consecutive draws where mode doesn't vary. */
206bf215546Sopenharmony_ci   for (i = 0, first = 0; i <= num_draws; i++) {
207bf215546Sopenharmony_ci      if (i == num_draws || mode[i] != mode[first]) {
208bf215546Sopenharmony_ci         info->mode = mode[first];
209bf215546Sopenharmony_ci         cso_multi_draw(cso, info, 0, &draws[first], i - first);
210bf215546Sopenharmony_ci         first = i;
211bf215546Sopenharmony_ci
212bf215546Sopenharmony_ci         /* We can pass the reference only once. st_buffer_object keeps
213bf215546Sopenharmony_ci          * the reference alive for later draws.
214bf215546Sopenharmony_ci          */
215bf215546Sopenharmony_ci         info->take_index_buffer_ownership = false;
216bf215546Sopenharmony_ci      }
217bf215546Sopenharmony_ci   }
218bf215546Sopenharmony_ci}
219bf215546Sopenharmony_ci
220bf215546Sopenharmony_cistatic void
221bf215546Sopenharmony_cirewrite_partial_stride_indirect(struct st_context *st,
222bf215546Sopenharmony_ci                            const struct pipe_draw_info *info,
223bf215546Sopenharmony_ci                            const struct pipe_draw_indirect_info *indirect,
224bf215546Sopenharmony_ci                            const struct pipe_draw_start_count_bias draw)
225bf215546Sopenharmony_ci{
226bf215546Sopenharmony_ci   unsigned draw_count = 0;
227bf215546Sopenharmony_ci   struct u_indirect_params *new_draws = util_draw_indirect_read(st->pipe, info, indirect, &draw_count);
228bf215546Sopenharmony_ci   if (!new_draws)
229bf215546Sopenharmony_ci      return;
230bf215546Sopenharmony_ci   for (unsigned i = 0; i < draw_count; i++)
231bf215546Sopenharmony_ci      cso_draw_vbo(st->cso_context, &new_draws[i].info, i, NULL, new_draws[i].draw);
232bf215546Sopenharmony_ci   free(new_draws);
233bf215546Sopenharmony_ci}
234bf215546Sopenharmony_ci
235bf215546Sopenharmony_civoid
236bf215546Sopenharmony_cist_indirect_draw_vbo(struct gl_context *ctx,
237bf215546Sopenharmony_ci                     GLuint mode,
238bf215546Sopenharmony_ci                     struct gl_buffer_object *indirect_data,
239bf215546Sopenharmony_ci                     GLsizeiptr indirect_offset,
240bf215546Sopenharmony_ci                     unsigned draw_count,
241bf215546Sopenharmony_ci                     unsigned stride,
242bf215546Sopenharmony_ci                     struct gl_buffer_object *indirect_draw_count,
243bf215546Sopenharmony_ci                     GLsizeiptr indirect_draw_count_offset,
244bf215546Sopenharmony_ci                     const struct _mesa_index_buffer *ib,
245bf215546Sopenharmony_ci                     bool primitive_restart,
246bf215546Sopenharmony_ci                     unsigned restart_index)
247bf215546Sopenharmony_ci{
248bf215546Sopenharmony_ci   struct st_context *st = st_context(ctx);
249bf215546Sopenharmony_ci   struct pipe_draw_info info;
250bf215546Sopenharmony_ci   struct pipe_draw_indirect_info indirect;
251bf215546Sopenharmony_ci   struct pipe_draw_start_count_bias draw = {0};
252bf215546Sopenharmony_ci
253bf215546Sopenharmony_ci   assert(stride);
254bf215546Sopenharmony_ci   prepare_draw(st, ctx, ST_PIPELINE_RENDER_STATE_MASK, ST_PIPELINE_RENDER);
255bf215546Sopenharmony_ci
256bf215546Sopenharmony_ci   memset(&indirect, 0, sizeof(indirect));
257bf215546Sopenharmony_ci   util_draw_init_info(&info);
258bf215546Sopenharmony_ci   info.max_index = ~0u; /* so that u_vbuf can tell that it's unknown */
259bf215546Sopenharmony_ci
260bf215546Sopenharmony_ci   if (ib) {
261bf215546Sopenharmony_ci      struct gl_buffer_object *bufobj = ib->obj;
262bf215546Sopenharmony_ci
263bf215546Sopenharmony_ci      /* indices are always in a real VBO */
264bf215546Sopenharmony_ci      assert(bufobj);
265bf215546Sopenharmony_ci
266bf215546Sopenharmony_ci      info.index_size = 1 << ib->index_size_shift;
267bf215546Sopenharmony_ci      info.index.resource = bufobj->buffer;
268bf215546Sopenharmony_ci      draw.start = pointer_to_offset(ib->ptr) >> ib->index_size_shift;
269bf215546Sopenharmony_ci
270bf215546Sopenharmony_ci      info.restart_index = restart_index;
271bf215546Sopenharmony_ci      info.primitive_restart = primitive_restart;
272bf215546Sopenharmony_ci   }
273bf215546Sopenharmony_ci
274bf215546Sopenharmony_ci   info.mode = translate_prim(ctx, mode);
275bf215546Sopenharmony_ci   indirect.buffer = indirect_data->buffer;
276bf215546Sopenharmony_ci   indirect.offset = indirect_offset;
277bf215546Sopenharmony_ci
278bf215546Sopenharmony_ci   /* Viewperf2020/Maya draws with a buffer that has no storage. */
279bf215546Sopenharmony_ci   if (!indirect.buffer)
280bf215546Sopenharmony_ci      return;
281bf215546Sopenharmony_ci
282bf215546Sopenharmony_ci   if (!st->has_multi_draw_indirect) {
283bf215546Sopenharmony_ci      int i;
284bf215546Sopenharmony_ci
285bf215546Sopenharmony_ci      assert(!indirect_draw_count);
286bf215546Sopenharmony_ci      indirect.draw_count = 1;
287bf215546Sopenharmony_ci      for (i = 0; i < draw_count; i++) {
288bf215546Sopenharmony_ci         cso_draw_vbo(st->cso_context, &info, i, &indirect, draw);
289bf215546Sopenharmony_ci         indirect.offset += stride;
290bf215546Sopenharmony_ci      }
291bf215546Sopenharmony_ci   } else {
292bf215546Sopenharmony_ci      indirect.draw_count = draw_count;
293bf215546Sopenharmony_ci      indirect.stride = stride;
294bf215546Sopenharmony_ci      if (!st->has_indirect_partial_stride && stride &&
295bf215546Sopenharmony_ci          (draw_count > 1 || indirect_draw_count)) {
296bf215546Sopenharmony_ci         /* DrawElementsIndirectCommand or DrawArraysIndirectCommand */
297bf215546Sopenharmony_ci         const size_t struct_size = info.index_size ? sizeof(uint32_t) * 5 : sizeof(uint32_t) * 4;
298bf215546Sopenharmony_ci         if (indirect.stride && indirect.stride < struct_size) {
299bf215546Sopenharmony_ci            rewrite_partial_stride_indirect(st, &info, &indirect, draw);
300bf215546Sopenharmony_ci            return;
301bf215546Sopenharmony_ci         }
302bf215546Sopenharmony_ci      }
303bf215546Sopenharmony_ci      if (indirect_draw_count) {
304bf215546Sopenharmony_ci         indirect.indirect_draw_count =
305bf215546Sopenharmony_ci            indirect_draw_count->buffer;
306bf215546Sopenharmony_ci         indirect.indirect_draw_count_offset = indirect_draw_count_offset;
307bf215546Sopenharmony_ci      }
308bf215546Sopenharmony_ci      cso_draw_vbo(st->cso_context, &info, 0, &indirect, draw);
309bf215546Sopenharmony_ci   }
310bf215546Sopenharmony_ci}
311bf215546Sopenharmony_ci
312bf215546Sopenharmony_civoid
313bf215546Sopenharmony_cist_draw_transform_feedback(struct gl_context *ctx, GLenum mode,
314bf215546Sopenharmony_ci                           unsigned num_instances, unsigned stream,
315bf215546Sopenharmony_ci                           struct gl_transform_feedback_object *tfb_vertcount)
316bf215546Sopenharmony_ci{
317bf215546Sopenharmony_ci   struct st_context *st = st_context(ctx);
318bf215546Sopenharmony_ci   struct pipe_draw_info info;
319bf215546Sopenharmony_ci   struct pipe_draw_indirect_info indirect;
320bf215546Sopenharmony_ci   struct pipe_draw_start_count_bias draw = {0};
321bf215546Sopenharmony_ci
322bf215546Sopenharmony_ci   prepare_draw(st, ctx, ST_PIPELINE_RENDER_STATE_MASK, ST_PIPELINE_RENDER);
323bf215546Sopenharmony_ci
324bf215546Sopenharmony_ci   memset(&indirect, 0, sizeof(indirect));
325bf215546Sopenharmony_ci   util_draw_init_info(&info);
326bf215546Sopenharmony_ci   info.max_index = ~0u; /* so that u_vbuf can tell that it's unknown */
327bf215546Sopenharmony_ci   info.mode = translate_prim(ctx, mode);
328bf215546Sopenharmony_ci   info.instance_count = num_instances;
329bf215546Sopenharmony_ci
330bf215546Sopenharmony_ci   /* Transform feedback drawing is always non-indexed. */
331bf215546Sopenharmony_ci   /* Set info.count_from_stream_output. */
332bf215546Sopenharmony_ci   indirect.count_from_stream_output = tfb_vertcount->draw_count[stream];
333bf215546Sopenharmony_ci   if (indirect.count_from_stream_output == NULL)
334bf215546Sopenharmony_ci      return;
335bf215546Sopenharmony_ci
336bf215546Sopenharmony_ci   cso_draw_vbo(st->cso_context, &info, 0, &indirect, draw);
337bf215546Sopenharmony_ci}
338bf215546Sopenharmony_ci
339bf215546Sopenharmony_cistatic void
340bf215546Sopenharmony_cist_draw_gallium_vertex_state(struct gl_context *ctx,
341bf215546Sopenharmony_ci                             struct pipe_vertex_state *state,
342bf215546Sopenharmony_ci                             struct pipe_draw_vertex_state_info info,
343bf215546Sopenharmony_ci                             const struct pipe_draw_start_count_bias *draws,
344bf215546Sopenharmony_ci                             const uint8_t *mode,
345bf215546Sopenharmony_ci                             unsigned num_draws,
346bf215546Sopenharmony_ci                             bool per_vertex_edgeflags)
347bf215546Sopenharmony_ci{
348bf215546Sopenharmony_ci   struct st_context *st = st_context(ctx);
349bf215546Sopenharmony_ci   bool old_vertdata_edgeflags = st->vertdata_edgeflags;
350bf215546Sopenharmony_ci
351bf215546Sopenharmony_ci   /* We don't flag any other states to make st_validate state update edge
352bf215546Sopenharmony_ci    * flags, so we need to update them here.
353bf215546Sopenharmony_ci    */
354bf215546Sopenharmony_ci   st_update_edgeflags(st, per_vertex_edgeflags);
355bf215546Sopenharmony_ci
356bf215546Sopenharmony_ci   prepare_draw(st, ctx, ST_PIPELINE_RENDER_STATE_MASK_NO_VARRAYS,
357bf215546Sopenharmony_ci                ST_PIPELINE_RENDER_NO_VARRAYS);
358bf215546Sopenharmony_ci
359bf215546Sopenharmony_ci   struct pipe_context *pipe = st->pipe;
360bf215546Sopenharmony_ci   uint32_t velem_mask = ctx->VertexProgram._Current->info.inputs_read;
361bf215546Sopenharmony_ci
362bf215546Sopenharmony_ci   if (!mode) {
363bf215546Sopenharmony_ci      pipe->draw_vertex_state(pipe, state, velem_mask, info, draws, num_draws);
364bf215546Sopenharmony_ci   } else {
365bf215546Sopenharmony_ci      /* Find consecutive draws where mode doesn't vary. */
366bf215546Sopenharmony_ci      for (unsigned i = 0, first = 0; i <= num_draws; i++) {
367bf215546Sopenharmony_ci         if (i == num_draws || mode[i] != mode[first]) {
368bf215546Sopenharmony_ci            unsigned current_num_draws = i - first;
369bf215546Sopenharmony_ci
370bf215546Sopenharmony_ci            /* Increase refcount to be able to use take_vertex_state_ownership
371bf215546Sopenharmony_ci             * with all draws.
372bf215546Sopenharmony_ci             */
373bf215546Sopenharmony_ci            if (i != num_draws && info.take_vertex_state_ownership)
374bf215546Sopenharmony_ci               p_atomic_inc(&state->reference.count);
375bf215546Sopenharmony_ci
376bf215546Sopenharmony_ci            info.mode = mode[first];
377bf215546Sopenharmony_ci            pipe->draw_vertex_state(pipe, state, velem_mask, info, &draws[first],
378bf215546Sopenharmony_ci                                    current_num_draws);
379bf215546Sopenharmony_ci            first = i;
380bf215546Sopenharmony_ci         }
381bf215546Sopenharmony_ci      }
382bf215546Sopenharmony_ci   }
383bf215546Sopenharmony_ci
384bf215546Sopenharmony_ci   /* If per-vertex edge flags are different than the non-display-list state,
385bf215546Sopenharmony_ci    *  just flag ST_NEW_VERTEX_ARRAY, which will also completely revalidate
386bf215546Sopenharmony_ci    * edge flags in st_validate_state.
387bf215546Sopenharmony_ci    */
388bf215546Sopenharmony_ci   if (st->vertdata_edgeflags != old_vertdata_edgeflags) {
389bf215546Sopenharmony_ci      ctx->Array.NewVertexElements = true;
390bf215546Sopenharmony_ci      st->dirty |= ST_NEW_VERTEX_ARRAYS;
391bf215546Sopenharmony_ci   }
392bf215546Sopenharmony_ci}
393bf215546Sopenharmony_ci
394bf215546Sopenharmony_civoid
395bf215546Sopenharmony_cist_init_draw_functions(struct pipe_screen *screen,
396bf215546Sopenharmony_ci                       struct dd_function_table *functions)
397bf215546Sopenharmony_ci{
398bf215546Sopenharmony_ci   functions->DrawGallium = st_draw_gallium;
399bf215546Sopenharmony_ci   functions->DrawGalliumMultiMode = st_draw_gallium_multimode;
400bf215546Sopenharmony_ci
401bf215546Sopenharmony_ci   if (screen->get_param(screen, PIPE_CAP_DRAW_VERTEX_STATE)) {
402bf215546Sopenharmony_ci      functions->DrawGalliumVertexState = st_draw_gallium_vertex_state;
403bf215546Sopenharmony_ci      functions->CreateGalliumVertexState = st_create_gallium_vertex_state;
404bf215546Sopenharmony_ci   }
405bf215546Sopenharmony_ci}
406bf215546Sopenharmony_ci
407bf215546Sopenharmony_ci
408bf215546Sopenharmony_civoid
409bf215546Sopenharmony_cist_destroy_draw(struct st_context *st)
410bf215546Sopenharmony_ci{
411bf215546Sopenharmony_ci   draw_destroy(st->draw);
412bf215546Sopenharmony_ci}
413bf215546Sopenharmony_ci
414bf215546Sopenharmony_ci/**
415bf215546Sopenharmony_ci * Getter for the draw_context, so that initialization of it can happen only
416bf215546Sopenharmony_ci * when needed (the TGSI exec machines take up quite a bit of memory).
417bf215546Sopenharmony_ci */
418bf215546Sopenharmony_cistruct draw_context *
419bf215546Sopenharmony_cist_get_draw_context(struct st_context *st)
420bf215546Sopenharmony_ci{
421bf215546Sopenharmony_ci   if (!st->draw) {
422bf215546Sopenharmony_ci      st->draw = draw_create(st->pipe);
423bf215546Sopenharmony_ci      if (!st->draw) {
424bf215546Sopenharmony_ci         _mesa_error(st->ctx, GL_OUT_OF_MEMORY, "feedback fallback allocation");
425bf215546Sopenharmony_ci         return NULL;
426bf215546Sopenharmony_ci      }
427bf215546Sopenharmony_ci   }
428bf215546Sopenharmony_ci
429bf215546Sopenharmony_ci   /* Disable draw options that might convert points/lines to tris, etc.
430bf215546Sopenharmony_ci    * as that would foul-up feedback/selection mode.
431bf215546Sopenharmony_ci    */
432bf215546Sopenharmony_ci   draw_wide_line_threshold(st->draw, 1000.0f);
433bf215546Sopenharmony_ci   draw_wide_point_threshold(st->draw, 1000.0f);
434bf215546Sopenharmony_ci   draw_enable_line_stipple(st->draw, FALSE);
435bf215546Sopenharmony_ci   draw_enable_point_sprites(st->draw, FALSE);
436bf215546Sopenharmony_ci
437bf215546Sopenharmony_ci   return st->draw;
438bf215546Sopenharmony_ci}
439bf215546Sopenharmony_ci
440bf215546Sopenharmony_ci/**
441bf215546Sopenharmony_ci * Draw a quad with given position, texcoords and color.
442bf215546Sopenharmony_ci */
443bf215546Sopenharmony_cibool
444bf215546Sopenharmony_cist_draw_quad(struct st_context *st,
445bf215546Sopenharmony_ci             float x0, float y0, float x1, float y1, float z,
446bf215546Sopenharmony_ci             float s0, float t0, float s1, float t1,
447bf215546Sopenharmony_ci             const float *color,
448bf215546Sopenharmony_ci             unsigned num_instances)
449bf215546Sopenharmony_ci{
450bf215546Sopenharmony_ci   struct pipe_vertex_buffer vb = {0};
451bf215546Sopenharmony_ci   struct st_util_vertex *verts;
452bf215546Sopenharmony_ci
453bf215546Sopenharmony_ci   vb.stride = sizeof(struct st_util_vertex);
454bf215546Sopenharmony_ci
455bf215546Sopenharmony_ci   u_upload_alloc(st->pipe->stream_uploader, 0,
456bf215546Sopenharmony_ci                  4 * sizeof(struct st_util_vertex), 4,
457bf215546Sopenharmony_ci                  &vb.buffer_offset, &vb.buffer.resource, (void **) &verts);
458bf215546Sopenharmony_ci   if (!vb.buffer.resource) {
459bf215546Sopenharmony_ci      return false;
460bf215546Sopenharmony_ci   }
461bf215546Sopenharmony_ci
462bf215546Sopenharmony_ci   /* lower-left */
463bf215546Sopenharmony_ci   verts[0].x = x0;
464bf215546Sopenharmony_ci   verts[0].y = y1;
465bf215546Sopenharmony_ci   verts[0].z = z;
466bf215546Sopenharmony_ci   verts[0].r = color[0];
467bf215546Sopenharmony_ci   verts[0].g = color[1];
468bf215546Sopenharmony_ci   verts[0].b = color[2];
469bf215546Sopenharmony_ci   verts[0].a = color[3];
470bf215546Sopenharmony_ci   verts[0].s = s0;
471bf215546Sopenharmony_ci   verts[0].t = t0;
472bf215546Sopenharmony_ci
473bf215546Sopenharmony_ci   /* lower-right */
474bf215546Sopenharmony_ci   verts[1].x = x1;
475bf215546Sopenharmony_ci   verts[1].y = y1;
476bf215546Sopenharmony_ci   verts[1].z = z;
477bf215546Sopenharmony_ci   verts[1].r = color[0];
478bf215546Sopenharmony_ci   verts[1].g = color[1];
479bf215546Sopenharmony_ci   verts[1].b = color[2];
480bf215546Sopenharmony_ci   verts[1].a = color[3];
481bf215546Sopenharmony_ci   verts[1].s = s1;
482bf215546Sopenharmony_ci   verts[1].t = t0;
483bf215546Sopenharmony_ci
484bf215546Sopenharmony_ci   /* upper-right */
485bf215546Sopenharmony_ci   verts[2].x = x1;
486bf215546Sopenharmony_ci   verts[2].y = y0;
487bf215546Sopenharmony_ci   verts[2].z = z;
488bf215546Sopenharmony_ci   verts[2].r = color[0];
489bf215546Sopenharmony_ci   verts[2].g = color[1];
490bf215546Sopenharmony_ci   verts[2].b = color[2];
491bf215546Sopenharmony_ci   verts[2].a = color[3];
492bf215546Sopenharmony_ci   verts[2].s = s1;
493bf215546Sopenharmony_ci   verts[2].t = t1;
494bf215546Sopenharmony_ci
495bf215546Sopenharmony_ci   /* upper-left */
496bf215546Sopenharmony_ci   verts[3].x = x0;
497bf215546Sopenharmony_ci   verts[3].y = y0;
498bf215546Sopenharmony_ci   verts[3].z = z;
499bf215546Sopenharmony_ci   verts[3].r = color[0];
500bf215546Sopenharmony_ci   verts[3].g = color[1];
501bf215546Sopenharmony_ci   verts[3].b = color[2];
502bf215546Sopenharmony_ci   verts[3].a = color[3];
503bf215546Sopenharmony_ci   verts[3].s = s0;
504bf215546Sopenharmony_ci   verts[3].t = t1;
505bf215546Sopenharmony_ci
506bf215546Sopenharmony_ci   u_upload_unmap(st->pipe->stream_uploader);
507bf215546Sopenharmony_ci
508bf215546Sopenharmony_ci   cso_set_vertex_buffers(st->cso_context, 0, 1, 0, false, &vb);
509bf215546Sopenharmony_ci   st->last_num_vbuffers = MAX2(st->last_num_vbuffers, 1);
510bf215546Sopenharmony_ci
511bf215546Sopenharmony_ci   if (num_instances > 1) {
512bf215546Sopenharmony_ci      cso_draw_arrays_instanced(st->cso_context, PIPE_PRIM_TRIANGLE_FAN, 0, 4,
513bf215546Sopenharmony_ci                                0, num_instances);
514bf215546Sopenharmony_ci   } else {
515bf215546Sopenharmony_ci      cso_draw_arrays(st->cso_context, PIPE_PRIM_TRIANGLE_FAN, 0, 4);
516bf215546Sopenharmony_ci   }
517bf215546Sopenharmony_ci
518bf215546Sopenharmony_ci   pipe_resource_reference(&vb.buffer.resource, NULL);
519bf215546Sopenharmony_ci
520bf215546Sopenharmony_ci   return true;
521bf215546Sopenharmony_ci}
522bf215546Sopenharmony_ci
523bf215546Sopenharmony_cistatic void
524bf215546Sopenharmony_cist_hw_select_draw_gallium(struct gl_context *ctx,
525bf215546Sopenharmony_ci                          struct pipe_draw_info *info,
526bf215546Sopenharmony_ci                          unsigned drawid_offset,
527bf215546Sopenharmony_ci                          const struct pipe_draw_start_count_bias *draws,
528bf215546Sopenharmony_ci                          unsigned num_draws)
529bf215546Sopenharmony_ci{
530bf215546Sopenharmony_ci   struct st_context *st = st_context(ctx);
531bf215546Sopenharmony_ci
532bf215546Sopenharmony_ci   prepare_draw(st, ctx, ST_PIPELINE_RENDER_STATE_MASK, ST_PIPELINE_RENDER);
533bf215546Sopenharmony_ci
534bf215546Sopenharmony_ci   if (!prepare_indexed_draw(st, ctx, info, draws, num_draws))
535bf215546Sopenharmony_ci      return;
536bf215546Sopenharmony_ci
537bf215546Sopenharmony_ci   if (!st_draw_hw_select_prepare_common(ctx) ||
538bf215546Sopenharmony_ci       !st_draw_hw_select_prepare_mode(ctx, info))
539bf215546Sopenharmony_ci      return;
540bf215546Sopenharmony_ci
541bf215546Sopenharmony_ci   cso_multi_draw(st->cso_context, info, drawid_offset, draws, num_draws);
542bf215546Sopenharmony_ci}
543bf215546Sopenharmony_ci
544bf215546Sopenharmony_cistatic void
545bf215546Sopenharmony_cist_hw_select_draw_gallium_multimode(struct gl_context *ctx,
546bf215546Sopenharmony_ci                                    struct pipe_draw_info *info,
547bf215546Sopenharmony_ci                                    const struct pipe_draw_start_count_bias *draws,
548bf215546Sopenharmony_ci                                    const unsigned char *mode,
549bf215546Sopenharmony_ci                                    unsigned num_draws)
550bf215546Sopenharmony_ci{
551bf215546Sopenharmony_ci   struct st_context *st = st_context(ctx);
552bf215546Sopenharmony_ci
553bf215546Sopenharmony_ci   prepare_draw(st, ctx, ST_PIPELINE_RENDER_STATE_MASK, ST_PIPELINE_RENDER);
554bf215546Sopenharmony_ci
555bf215546Sopenharmony_ci   if (!prepare_indexed_draw(st, ctx, info, draws, num_draws))
556bf215546Sopenharmony_ci      return;
557bf215546Sopenharmony_ci
558bf215546Sopenharmony_ci   if (!st_draw_hw_select_prepare_common(ctx))
559bf215546Sopenharmony_ci      return;
560bf215546Sopenharmony_ci
561bf215546Sopenharmony_ci   unsigned i, first;
562bf215546Sopenharmony_ci   struct cso_context *cso = st->cso_context;
563bf215546Sopenharmony_ci
564bf215546Sopenharmony_ci   /* Find consecutive draws where mode doesn't vary. */
565bf215546Sopenharmony_ci   for (i = 0, first = 0; i <= num_draws; i++) {
566bf215546Sopenharmony_ci      if (i == num_draws || mode[i] != mode[first]) {
567bf215546Sopenharmony_ci         info->mode = mode[first];
568bf215546Sopenharmony_ci
569bf215546Sopenharmony_ci         if (st_draw_hw_select_prepare_mode(ctx, info))
570bf215546Sopenharmony_ci            cso_multi_draw(cso, info, 0, &draws[first], i - first);
571bf215546Sopenharmony_ci
572bf215546Sopenharmony_ci         first = i;
573bf215546Sopenharmony_ci
574bf215546Sopenharmony_ci         /* We can pass the reference only once. st_buffer_object keeps
575bf215546Sopenharmony_ci          * the reference alive for later draws.
576bf215546Sopenharmony_ci          */
577bf215546Sopenharmony_ci         info->take_index_buffer_ownership = false;
578bf215546Sopenharmony_ci      }
579bf215546Sopenharmony_ci   }
580bf215546Sopenharmony_ci}
581bf215546Sopenharmony_ci
582bf215546Sopenharmony_civoid
583bf215546Sopenharmony_cist_init_hw_select_draw_functions(struct pipe_screen *screen,
584bf215546Sopenharmony_ci                                 struct dd_function_table *functions)
585bf215546Sopenharmony_ci{
586bf215546Sopenharmony_ci   functions->DrawGallium = st_hw_select_draw_gallium;
587bf215546Sopenharmony_ci   functions->DrawGalliumMultiMode = st_hw_select_draw_gallium_multimode;
588bf215546Sopenharmony_ci}
589