14a49301eSmrg/**************************************************************************
2af69d88dSmrg *
3af69d88dSmrg * Copyright 2007 VMware, Inc.
44a49301eSmrg * All Rights Reserved.
5af69d88dSmrg *
64a49301eSmrg * Permission is hereby granted, free of charge, to any person obtaining a
74a49301eSmrg * copy of this software and associated documentation files (the
84a49301eSmrg * "Software"), to deal in the Software without restriction, including
94a49301eSmrg * without limitation the rights to use, copy, modify, merge, publish,
104a49301eSmrg * distribute, sub license, and/or sell copies of the Software, and to
114a49301eSmrg * permit persons to whom the Software is furnished to do so, subject to
124a49301eSmrg * the following conditions:
13af69d88dSmrg *
144a49301eSmrg * The above copyright notice and this permission notice (including the
154a49301eSmrg * next paragraph) shall be included in all copies or substantial portions
164a49301eSmrg * of the Software.
17af69d88dSmrg *
184a49301eSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
194a49301eSmrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
204a49301eSmrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21af69d88dSmrg * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
224a49301eSmrg * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
234a49301eSmrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
244a49301eSmrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25af69d88dSmrg *
264a49301eSmrg **************************************************************************/
274a49301eSmrg
284a49301eSmrg/*
294a49301eSmrg * This file implements the st_draw_vbo() function which is called from
304a49301eSmrg * Mesa's VBO module.  All point/line/triangle rendering is done through
314a49301eSmrg * this function whether the user called glBegin/End, glDrawArrays,
324a49301eSmrg * glDrawElements, glEvalMesh, or glCalList, etc.
334a49301eSmrg *
344a49301eSmrg * Authors:
35af69d88dSmrg *   Keith Whitwell <keithw@vmware.com>
364a49301eSmrg */
374a49301eSmrg
384a49301eSmrg
3901e04c3fSmrg#include "main/errors.h"
407ec681f3Smrg
414a49301eSmrg#include "main/image.h"
423464ebd5Sriastradh#include "main/bufferobj.h"
434a49301eSmrg#include "main/macros.h"
4401e04c3fSmrg#include "main/varray.h"
4501e04c3fSmrg
4601e04c3fSmrg#include "compiler/glsl/ir_uniform.h"
474a49301eSmrg
484a49301eSmrg#include "vbo/vbo.h"
494a49301eSmrg
504a49301eSmrg#include "st_context.h"
514a49301eSmrg#include "st_atom.h"
5201e04c3fSmrg#include "st_cb_bitmap.h"
534a49301eSmrg#include "st_cb_bufferobjects.h"
54af69d88dSmrg#include "st_cb_xformfb.h"
55af69d88dSmrg#include "st_debug.h"
564a49301eSmrg#include "st_draw.h"
574a49301eSmrg#include "st_program.h"
58b9abf16eSmaya#include "st_util.h"
594a49301eSmrg
604a49301eSmrg#include "pipe/p_context.h"
614a49301eSmrg#include "pipe/p_defines.h"
62b9abf16eSmaya#include "util/u_cpu_detect.h"
63cdc920a0Smrg#include "util/u_inlines.h"
647ec681f3Smrg#include "util/format/u_format.h"
653464ebd5Sriastradh#include "util/u_prim.h"
6601e04c3fSmrg#include "util/u_draw.h"
67af69d88dSmrg#include "util/u_upload_mgr.h"
687ec681f3Smrg#include "util/u_threaded_context.h"
693464ebd5Sriastradh#include "draw/draw_context.h"
703464ebd5Sriastradh#include "cso_cache/cso_context.h"
714a49301eSmrg
724a49301eSmrg
733464ebd5Sriastradh/**
743464ebd5Sriastradh * Translate OpenGL primtive type (GL_POINTS, GL_TRIANGLE_STRIP, etc) to
753464ebd5Sriastradh * the corresponding Gallium type.
763464ebd5Sriastradh */
773464ebd5Sriastradhstatic unsigned
783464ebd5Sriastradhtranslate_prim(const struct gl_context *ctx, unsigned prim)
79cdc920a0Smrg{
803464ebd5Sriastradh   /* GL prims should match Gallium prims, spot-check a few */
81af69d88dSmrg   STATIC_ASSERT(GL_POINTS == PIPE_PRIM_POINTS);
82af69d88dSmrg   STATIC_ASSERT(GL_QUADS == PIPE_PRIM_QUADS);
83af69d88dSmrg   STATIC_ASSERT(GL_TRIANGLE_STRIP_ADJACENCY == PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY);
8401e04c3fSmrg   STATIC_ASSERT(GL_PATCHES == PIPE_PRIM_PATCHES);
85cdc920a0Smrg
86cdc920a0Smrg   return prim;
87cdc920a0Smrg}
88cdc920a0Smrg
8901e04c3fSmrgstatic inline void
907ec681f3Smrgprepare_draw(struct st_context *st, struct gl_context *ctx, uint64_t state_mask,
917ec681f3Smrg             enum st_pipeline pipeline)
9201e04c3fSmrg{
9301e04c3fSmrg   /* Mesa core state should have been validated already */
9401e04c3fSmrg   assert(ctx->NewState == 0x0);
9501e04c3fSmrg
9601e04c3fSmrg   if (unlikely(!st->bitmap.cache.empty))
9701e04c3fSmrg      st_flush_bitmap_cache(st);
9801e04c3fSmrg
9901e04c3fSmrg   st_invalidate_readpix_cache(st);
10001e04c3fSmrg
10101e04c3fSmrg   /* Validate state. */
1027ec681f3Smrg   if ((st->dirty | ctx->NewDriverState) & st->active_states & state_mask ||
10301e04c3fSmrg       st->gfx_shaders_may_be_dirty) {
1047ec681f3Smrg      st_validate_state(st, pipeline);
10501e04c3fSmrg   }
106b9abf16eSmaya
107b9abf16eSmaya   /* Pin threads regularly to the same Zen CCX that the main thread is
108b9abf16eSmaya    * running on. The main thread can move between CCXs.
109b9abf16eSmaya    */
1107ec681f3Smrg   if (unlikely(st->pin_thread_counter != ST_L3_PINNING_DISABLED &&
111b9abf16eSmaya                /* no glthread */
112b9abf16eSmaya                ctx->CurrentClientDispatch != ctx->MarshalExec &&
113b9abf16eSmaya                /* do it occasionally */
114b9abf16eSmaya                ++st->pin_thread_counter % 512 == 0)) {
1157ec681f3Smrg      st->pin_thread_counter = 0;
1167ec681f3Smrg
1177ec681f3Smrg      int cpu = util_get_current_cpu();
118b9abf16eSmaya      if (cpu >= 0) {
1197ec681f3Smrg         struct pipe_context *pipe = st->pipe;
1207ec681f3Smrg         uint16_t L3_cache = util_get_cpu_caps()->cpu_to_L3[cpu];
1217ec681f3Smrg
1227ec681f3Smrg         if (L3_cache != U_CPU_INVALID_L3) {
1237ec681f3Smrg            pipe->set_context_param(pipe,
1247ec681f3Smrg                                    PIPE_CONTEXT_PARAM_PIN_THREADS_TO_L3_CACHE,
1257ec681f3Smrg                                    L3_cache);
1267ec681f3Smrg         }
1277ec681f3Smrg      }
1287ec681f3Smrg   }
1297ec681f3Smrg}
1307ec681f3Smrg
1317ec681f3Smrgstatic bool ALWAYS_INLINE
1327ec681f3Smrgprepare_indexed_draw(/* pass both st and ctx to reduce dereferences */
1337ec681f3Smrg                     struct st_context *st,
1347ec681f3Smrg                     struct gl_context *ctx,
1357ec681f3Smrg                     struct pipe_draw_info *info,
1367ec681f3Smrg                     const struct pipe_draw_start_count_bias *draws,
1377ec681f3Smrg                     unsigned num_draws)
1387ec681f3Smrg{
1397ec681f3Smrg   if (info->index_size) {
1407ec681f3Smrg      /* Get index bounds for user buffers. */
1417ec681f3Smrg      if (!info->index_bounds_valid &&
1427ec681f3Smrg          st->draw_needs_minmax_index) {
1437ec681f3Smrg         /* Return if this fails, which means all draws have count == 0. */
1447ec681f3Smrg         if (!vbo_get_minmax_indices_gallium(ctx, info, draws, num_draws))
1457ec681f3Smrg            return false;
146b9abf16eSmaya
1477ec681f3Smrg         info->index_bounds_valid = true;
1487ec681f3Smrg      }
1497ec681f3Smrg
1507ec681f3Smrg      if (!info->has_user_indices) {
1517ec681f3Smrg         if (st->pipe->draw_vbo == tc_draw_vbo) {
1527ec681f3Smrg            /* Fast path for u_threaded_context. This eliminates the atomic
1537ec681f3Smrg             * increment for the index buffer refcount when adding it into
1547ec681f3Smrg             * the threaded batch buffer.
1557ec681f3Smrg             */
1567ec681f3Smrg            info->index.resource =
1577ec681f3Smrg               st_get_buffer_reference(ctx, info->index.gl_bo);
1587ec681f3Smrg            info->take_index_buffer_ownership = true;
1597ec681f3Smrg         } else {
1607ec681f3Smrg            info->index.resource = st_buffer_object(info->index.gl_bo)->buffer;
1617ec681f3Smrg         }
1627ec681f3Smrg
1637ec681f3Smrg         /* Return if the bound element array buffer doesn't have any backing
1647ec681f3Smrg          * storage. (nothing to do)
1657ec681f3Smrg          */
1667ec681f3Smrg         if (unlikely(!info->index.resource))
1677ec681f3Smrg            return false;
168b9abf16eSmaya      }
169b9abf16eSmaya   }
1707ec681f3Smrg   return true;
17101e04c3fSmrg}
1723464ebd5Sriastradh
17301e04c3fSmrgstatic void
1747ec681f3Smrgst_draw_gallium(struct gl_context *ctx,
1757ec681f3Smrg                struct pipe_draw_info *info,
1767ec681f3Smrg                unsigned drawid_offset,
1777ec681f3Smrg                const struct pipe_draw_start_count_bias *draws,
1787ec681f3Smrg                unsigned num_draws)
1793464ebd5Sriastradh{
1803464ebd5Sriastradh   struct st_context *st = st_context(ctx);
1813464ebd5Sriastradh
1827ec681f3Smrg   prepare_draw(st, ctx, ST_PIPELINE_RENDER_STATE_MASK, ST_PIPELINE_RENDER);
1834a49301eSmrg
1847ec681f3Smrg   if (!prepare_indexed_draw(st, ctx, info, draws, num_draws))
1857ec681f3Smrg      return;
186af69d88dSmrg
1877ec681f3Smrg   cso_multi_draw(st->cso_context, info, drawid_offset, draws, num_draws);
1887ec681f3Smrg}
18901e04c3fSmrg
1907ec681f3Smrgstatic void
1917ec681f3Smrgst_draw_gallium_multimode(struct gl_context *ctx,
1927ec681f3Smrg                          struct pipe_draw_info *info,
1937ec681f3Smrg                          const struct pipe_draw_start_count_bias *draws,
1947ec681f3Smrg                          const unsigned char *mode,
1957ec681f3Smrg                          unsigned num_draws)
1967ec681f3Smrg{
1977ec681f3Smrg   struct st_context *st = st_context(ctx);
198af69d88dSmrg
1997ec681f3Smrg   prepare_draw(st, ctx, ST_PIPELINE_RENDER_STATE_MASK, ST_PIPELINE_RENDER);
20001e04c3fSmrg
2017ec681f3Smrg   if (!prepare_indexed_draw(st, ctx, info, draws, num_draws))
2027ec681f3Smrg      return;
20301e04c3fSmrg
2047ec681f3Smrg   unsigned i, first;
2057ec681f3Smrg   struct cso_context *cso = st->cso_context;
206af69d88dSmrg
2077ec681f3Smrg   /* Find consecutive draws where mode doesn't vary. */
2087ec681f3Smrg   for (i = 0, first = 0; i <= num_draws; i++) {
2097ec681f3Smrg      if (i == num_draws || mode[i] != mode[first]) {
2107ec681f3Smrg         info->mode = mode[first];
2117ec681f3Smrg         cso_multi_draw(cso, info, 0, &draws[first], i - first);
2127ec681f3Smrg         first = i;
213af69d88dSmrg
2147ec681f3Smrg         /* We can pass the reference only once. st_buffer_object keeps
2157ec681f3Smrg          * the reference alive for later draws.
2167ec681f3Smrg          */
2177ec681f3Smrg         info->take_index_buffer_ownership = false;
218af69d88dSmrg      }
21901e04c3fSmrg   }
22001e04c3fSmrg}
22101e04c3fSmrg
22201e04c3fSmrgstatic void
22301e04c3fSmrgst_indirect_draw_vbo(struct gl_context *ctx,
22401e04c3fSmrg                     GLuint mode,
22501e04c3fSmrg                     struct gl_buffer_object *indirect_data,
22601e04c3fSmrg                     GLsizeiptr indirect_offset,
22701e04c3fSmrg                     unsigned draw_count,
22801e04c3fSmrg                     unsigned stride,
22901e04c3fSmrg                     struct gl_buffer_object *indirect_draw_count,
23001e04c3fSmrg                     GLsizeiptr indirect_draw_count_offset,
2317ec681f3Smrg                     const struct _mesa_index_buffer *ib,
2327ec681f3Smrg                     bool primitive_restart,
2337ec681f3Smrg                     unsigned restart_index)
23401e04c3fSmrg{
23501e04c3fSmrg   struct st_context *st = st_context(ctx);
23601e04c3fSmrg   struct pipe_draw_info info;
23701e04c3fSmrg   struct pipe_draw_indirect_info indirect;
2387ec681f3Smrg   struct pipe_draw_start_count_bias draw = {0};
23901e04c3fSmrg
24001e04c3fSmrg   assert(stride);
2417ec681f3Smrg   prepare_draw(st, ctx, ST_PIPELINE_RENDER_STATE_MASK, ST_PIPELINE_RENDER);
24201e04c3fSmrg
24301e04c3fSmrg   memset(&indirect, 0, sizeof(indirect));
24401e04c3fSmrg   util_draw_init_info(&info);
24501e04c3fSmrg   info.max_index = ~0u; /* so that u_vbuf can tell that it's unknown */
24601e04c3fSmrg
24701e04c3fSmrg   if (ib) {
24801e04c3fSmrg      struct gl_buffer_object *bufobj = ib->obj;
24901e04c3fSmrg
25001e04c3fSmrg      /* indices are always in a real VBO */
2517ec681f3Smrg      assert(bufobj);
25201e04c3fSmrg
2537ec681f3Smrg      info.index_size = 1 << ib->index_size_shift;
25401e04c3fSmrg      info.index.resource = st_buffer_object(bufobj)->buffer;
2557ec681f3Smrg      draw.start = pointer_to_offset(ib->ptr) >> ib->index_size_shift;
25601e04c3fSmrg
2577ec681f3Smrg      info.restart_index = restart_index;
2587ec681f3Smrg      info.primitive_restart = primitive_restart;
25901e04c3fSmrg   }
26001e04c3fSmrg
26101e04c3fSmrg   info.mode = translate_prim(ctx, mode);
26201e04c3fSmrg   indirect.buffer = st_buffer_object(indirect_data)->buffer;
26301e04c3fSmrg   indirect.offset = indirect_offset;
26401e04c3fSmrg
2657ec681f3Smrg   /* Viewperf2020/Maya draws with a buffer that has no storage. */
2667ec681f3Smrg   if (!indirect.buffer)
2677ec681f3Smrg      return;
26801e04c3fSmrg
26901e04c3fSmrg   if (!st->has_multi_draw_indirect) {
27001e04c3fSmrg      int i;
27101e04c3fSmrg
27201e04c3fSmrg      assert(!indirect_draw_count);
27301e04c3fSmrg      indirect.draw_count = 1;
27401e04c3fSmrg      for (i = 0; i < draw_count; i++) {
2757ec681f3Smrg         cso_draw_vbo(st->cso_context, &info, i, &indirect, draw);
27601e04c3fSmrg         indirect.offset += stride;
277af69d88dSmrg      }
27801e04c3fSmrg   } else {
27901e04c3fSmrg      indirect.draw_count = draw_count;
28001e04c3fSmrg      indirect.stride = stride;
28101e04c3fSmrg      if (indirect_draw_count) {
28201e04c3fSmrg         indirect.indirect_draw_count =
28301e04c3fSmrg            st_buffer_object(indirect_draw_count)->buffer;
28401e04c3fSmrg         indirect.indirect_draw_count_offset = indirect_draw_count_offset;
285af69d88dSmrg      }
2867ec681f3Smrg      cso_draw_vbo(st->cso_context, &info, 0, &indirect, draw);
287af69d88dSmrg   }
2884a49301eSmrg}
2894a49301eSmrg
2907ec681f3Smrgstatic void
2917ec681f3Smrgst_draw_transform_feedback(struct gl_context *ctx, GLenum mode,
2927ec681f3Smrg                           unsigned num_instances, unsigned stream,
2937ec681f3Smrg                           struct gl_transform_feedback_object *tfb_vertcount)
2947ec681f3Smrg{
2957ec681f3Smrg   struct st_context *st = st_context(ctx);
2967ec681f3Smrg   struct pipe_draw_info info;
2977ec681f3Smrg   struct pipe_draw_indirect_info indirect;
2987ec681f3Smrg   struct pipe_draw_start_count_bias draw = {0};
2997ec681f3Smrg
3007ec681f3Smrg   prepare_draw(st, ctx, ST_PIPELINE_RENDER_STATE_MASK, ST_PIPELINE_RENDER);
3017ec681f3Smrg
3027ec681f3Smrg   memset(&indirect, 0, sizeof(indirect));
3037ec681f3Smrg   util_draw_init_info(&info);
3047ec681f3Smrg   info.max_index = ~0u; /* so that u_vbuf can tell that it's unknown */
3057ec681f3Smrg   info.mode = translate_prim(ctx, mode);
3067ec681f3Smrg   info.instance_count = num_instances;
3077ec681f3Smrg
3087ec681f3Smrg   /* Transform feedback drawing is always non-indexed. */
3097ec681f3Smrg   /* Set info.count_from_stream_output. */
3107ec681f3Smrg   if (!st_transform_feedback_draw_init(tfb_vertcount, stream, &indirect))
3117ec681f3Smrg      return;
3127ec681f3Smrg
3137ec681f3Smrg   cso_draw_vbo(st->cso_context, &info, 0, &indirect, draw);
3147ec681f3Smrg}
3157ec681f3Smrg
3167ec681f3Smrgstatic void
3177ec681f3Smrgst_draw_gallium_vertex_state(struct gl_context *ctx,
3187ec681f3Smrg                             struct pipe_vertex_state *state,
3197ec681f3Smrg                             struct pipe_draw_vertex_state_info info,
3207ec681f3Smrg                             const struct pipe_draw_start_count_bias *draws,
3217ec681f3Smrg                             const uint8_t *mode,
3227ec681f3Smrg                             unsigned num_draws,
3237ec681f3Smrg                             bool per_vertex_edgeflags)
3247ec681f3Smrg{
3257ec681f3Smrg   struct st_context *st = st_context(ctx);
3267ec681f3Smrg   bool old_vertdata_edgeflags = st->vertdata_edgeflags;
3277ec681f3Smrg
3287ec681f3Smrg   /* We don't flag any other states to make st_validate state update edge
3297ec681f3Smrg    * flags, so we need to update them here.
3307ec681f3Smrg    */
3317ec681f3Smrg   st_update_edgeflags(st, per_vertex_edgeflags);
3327ec681f3Smrg
3337ec681f3Smrg   prepare_draw(st, ctx, ST_PIPELINE_RENDER_STATE_MASK_NO_VARRAYS,
3347ec681f3Smrg                ST_PIPELINE_RENDER_NO_VARRAYS);
3357ec681f3Smrg
3367ec681f3Smrg   struct pipe_context *pipe = st->pipe;
3377ec681f3Smrg   uint32_t velem_mask = ctx->VertexProgram._Current->info.inputs_read;
3387ec681f3Smrg
3397ec681f3Smrg   if (!mode) {
3407ec681f3Smrg      pipe->draw_vertex_state(pipe, state, velem_mask, info, draws, num_draws);
3417ec681f3Smrg   } else {
3427ec681f3Smrg      /* Find consecutive draws where mode doesn't vary. */
3437ec681f3Smrg      for (unsigned i = 0, first = 0; i <= num_draws; i++) {
3447ec681f3Smrg         if (i == num_draws || mode[i] != mode[first]) {
3457ec681f3Smrg            unsigned current_num_draws = i - first;
3467ec681f3Smrg
3477ec681f3Smrg            /* Increase refcount to be able to use take_vertex_state_ownership
3487ec681f3Smrg             * with all draws.
3497ec681f3Smrg             */
3507ec681f3Smrg            if (i != num_draws && info.take_vertex_state_ownership)
3517ec681f3Smrg               p_atomic_inc(&state->reference.count);
3527ec681f3Smrg
3537ec681f3Smrg            info.mode = mode[first];
3547ec681f3Smrg            pipe->draw_vertex_state(pipe, state, velem_mask, info, &draws[first],
3557ec681f3Smrg                                    current_num_draws);
3567ec681f3Smrg            first = i;
3577ec681f3Smrg         }
3587ec681f3Smrg      }
3597ec681f3Smrg   }
3607ec681f3Smrg
3617ec681f3Smrg   /* If per-vertex edge flags are different than the non-display-list state,
3627ec681f3Smrg    *  just flag ST_NEW_VERTEX_ARRAY, which will also completely revalidate
3637ec681f3Smrg    * edge flags in st_validate_state.
3647ec681f3Smrg    */
3657ec681f3Smrg   if (st->vertdata_edgeflags != old_vertdata_edgeflags)
3667ec681f3Smrg      st->dirty |= ST_NEW_VERTEX_ARRAYS;
3677ec681f3Smrg}
3684a49301eSmrg
3693464ebd5Sriastradhvoid
3707ec681f3Smrgst_init_draw_functions(struct pipe_screen *screen,
3717ec681f3Smrg                       struct dd_function_table *functions)
3724a49301eSmrg{
3737ec681f3Smrg   functions->Draw = NULL;
3747ec681f3Smrg   functions->DrawGallium = st_draw_gallium;
3757ec681f3Smrg   functions->DrawGalliumMultiMode = st_draw_gallium_multimode;
37601e04c3fSmrg   functions->DrawIndirect = st_indirect_draw_vbo;
3777ec681f3Smrg   functions->DrawTransformFeedback = st_draw_transform_feedback;
3787ec681f3Smrg
3797ec681f3Smrg   if (screen->get_param(screen, PIPE_CAP_DRAW_VERTEX_STATE)) {
3807ec681f3Smrg      functions->DrawGalliumVertexState = st_draw_gallium_vertex_state;
3817ec681f3Smrg      functions->CreateGalliumVertexState = st_create_gallium_vertex_state;
3827ec681f3Smrg   }
38301e04c3fSmrg}
3844a49301eSmrg
3854a49301eSmrg
38601e04c3fSmrgvoid
38701e04c3fSmrgst_destroy_draw(struct st_context *st)
38801e04c3fSmrg{
38901e04c3fSmrg   draw_destroy(st->draw);
39001e04c3fSmrg}
39101e04c3fSmrg
39201e04c3fSmrg/**
39301e04c3fSmrg * Getter for the draw_context, so that initialization of it can happen only
39401e04c3fSmrg * when needed (the TGSI exec machines take up quite a bit of memory).
39501e04c3fSmrg */
39601e04c3fSmrgstruct draw_context *
39701e04c3fSmrgst_get_draw_context(struct st_context *st)
39801e04c3fSmrg{
39901e04c3fSmrg   if (!st->draw) {
40001e04c3fSmrg      st->draw = draw_create(st->pipe);
40101e04c3fSmrg      if (!st->draw) {
40201e04c3fSmrg         _mesa_error(st->ctx, GL_OUT_OF_MEMORY, "feedback fallback allocation");
40301e04c3fSmrg         return NULL;
40401e04c3fSmrg      }
40501e04c3fSmrg   }
4064a49301eSmrg
4073464ebd5Sriastradh   /* Disable draw options that might convert points/lines to tris, etc.
4083464ebd5Sriastradh    * as that would foul-up feedback/selection mode.
4093464ebd5Sriastradh    */
4103464ebd5Sriastradh   draw_wide_line_threshold(st->draw, 1000.0f);
4113464ebd5Sriastradh   draw_wide_point_threshold(st->draw, 1000.0f);
4123464ebd5Sriastradh   draw_enable_line_stipple(st->draw, FALSE);
4133464ebd5Sriastradh   draw_enable_point_sprites(st->draw, FALSE);
4144a49301eSmrg
41501e04c3fSmrg   return st->draw;
41601e04c3fSmrg}
4174a49301eSmrg
41801e04c3fSmrg/**
41901e04c3fSmrg * Draw a quad with given position, texcoords and color.
42001e04c3fSmrg */
42101e04c3fSmrgbool
42201e04c3fSmrgst_draw_quad(struct st_context *st,
42301e04c3fSmrg             float x0, float y0, float x1, float y1, float z,
42401e04c3fSmrg             float s0, float t0, float s1, float t1,
42501e04c3fSmrg             const float *color,
42601e04c3fSmrg             unsigned num_instances)
4273464ebd5Sriastradh{
42801e04c3fSmrg   struct pipe_vertex_buffer vb = {0};
42901e04c3fSmrg   struct st_util_vertex *verts;
43001e04c3fSmrg
43101e04c3fSmrg   vb.stride = sizeof(struct st_util_vertex);
43201e04c3fSmrg
43301e04c3fSmrg   u_upload_alloc(st->pipe->stream_uploader, 0,
43401e04c3fSmrg                  4 * sizeof(struct st_util_vertex), 4,
43501e04c3fSmrg                  &vb.buffer_offset, &vb.buffer.resource, (void **) &verts);
43601e04c3fSmrg   if (!vb.buffer.resource) {
43701e04c3fSmrg      return false;
43801e04c3fSmrg   }
43901e04c3fSmrg
44001e04c3fSmrg   /* lower-left */
44101e04c3fSmrg   verts[0].x = x0;
44201e04c3fSmrg   verts[0].y = y1;
44301e04c3fSmrg   verts[0].z = z;
44401e04c3fSmrg   verts[0].r = color[0];
44501e04c3fSmrg   verts[0].g = color[1];
44601e04c3fSmrg   verts[0].b = color[2];
44701e04c3fSmrg   verts[0].a = color[3];
44801e04c3fSmrg   verts[0].s = s0;
44901e04c3fSmrg   verts[0].t = t0;
45001e04c3fSmrg
45101e04c3fSmrg   /* lower-right */
45201e04c3fSmrg   verts[1].x = x1;
45301e04c3fSmrg   verts[1].y = y1;
45401e04c3fSmrg   verts[1].z = z;
45501e04c3fSmrg   verts[1].r = color[0];
45601e04c3fSmrg   verts[1].g = color[1];
45701e04c3fSmrg   verts[1].b = color[2];
45801e04c3fSmrg   verts[1].a = color[3];
45901e04c3fSmrg   verts[1].s = s1;
46001e04c3fSmrg   verts[1].t = t0;
46101e04c3fSmrg
46201e04c3fSmrg   /* upper-right */
46301e04c3fSmrg   verts[2].x = x1;
46401e04c3fSmrg   verts[2].y = y0;
46501e04c3fSmrg   verts[2].z = z;
46601e04c3fSmrg   verts[2].r = color[0];
46701e04c3fSmrg   verts[2].g = color[1];
46801e04c3fSmrg   verts[2].b = color[2];
46901e04c3fSmrg   verts[2].a = color[3];
47001e04c3fSmrg   verts[2].s = s1;
47101e04c3fSmrg   verts[2].t = t1;
47201e04c3fSmrg
47301e04c3fSmrg   /* upper-left */
47401e04c3fSmrg   verts[3].x = x0;
47501e04c3fSmrg   verts[3].y = y0;
47601e04c3fSmrg   verts[3].z = z;
47701e04c3fSmrg   verts[3].r = color[0];
47801e04c3fSmrg   verts[3].g = color[1];
47901e04c3fSmrg   verts[3].b = color[2];
48001e04c3fSmrg   verts[3].a = color[3];
48101e04c3fSmrg   verts[3].s = s0;
48201e04c3fSmrg   verts[3].t = t1;
48301e04c3fSmrg
48401e04c3fSmrg   u_upload_unmap(st->pipe->stream_uploader);
48501e04c3fSmrg
48601e04c3fSmrg   cso_set_vertex_buffers(st->cso_context, 0, 1, &vb);
4877ec681f3Smrg   st->last_num_vbuffers = MAX2(st->last_num_vbuffers, 1);
48801e04c3fSmrg
48901e04c3fSmrg   if (num_instances > 1) {
49001e04c3fSmrg      cso_draw_arrays_instanced(st->cso_context, PIPE_PRIM_TRIANGLE_FAN, 0, 4,
49101e04c3fSmrg                                0, num_instances);
49201e04c3fSmrg   } else {
49301e04c3fSmrg      cso_draw_arrays(st->cso_context, PIPE_PRIM_TRIANGLE_FAN, 0, 4);
49401e04c3fSmrg   }
49501e04c3fSmrg
49601e04c3fSmrg   pipe_resource_reference(&vb.buffer.resource, NULL);
49701e04c3fSmrg
49801e04c3fSmrg   return true;
4993464ebd5Sriastradh}
500