14a49301eSmrg/*
24a49301eSmrg * Copyright 2009 VMware, Inc.
34a49301eSmrg * All Rights Reserved.
44a49301eSmrg *
54a49301eSmrg * Permission is hereby granted, free of charge, to any person obtaining a
64a49301eSmrg * copy of this software and associated documentation files (the "Software"),
74a49301eSmrg * to deal in the Software without restriction, including without limitation
84a49301eSmrg * on the rights to use, copy, modify, merge, publish, distribute, sub
94a49301eSmrg * license, and/or sell copies of the Software, and to permit persons to whom
104a49301eSmrg * the Software is furnished to do so, subject to the following conditions:
114a49301eSmrg *
124a49301eSmrg * The above copyright notice and this permission notice (including the next
134a49301eSmrg * paragraph) shall be included in all copies or substantial portions of the
144a49301eSmrg * Software.
154a49301eSmrg *
164a49301eSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
174a49301eSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
184a49301eSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
194a49301eSmrg * VMWARE AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
204a49301eSmrg * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
214a49301eSmrg * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
224a49301eSmrg * USE OR OTHER DEALINGS IN THE SOFTWARE.
234a49301eSmrg */
244a49301eSmrg
254a49301eSmrg#include "u_indices.h"
264a49301eSmrg#include "u_indices_priv.h"
274a49301eSmrg
284a49301eSmrgstatic void translate_memcpy_ushort( const void *in,
29af69d88dSmrg                                     unsigned start,
3001e04c3fSmrg                                     unsigned in_nr,
3101e04c3fSmrg                                     unsigned out_nr,
3201e04c3fSmrg                                     unsigned restart_index,
334a49301eSmrg                                     void *out )
344a49301eSmrg{
3501e04c3fSmrg   memcpy(out, &((short *)in)[start], out_nr*sizeof(short));
364a49301eSmrg}
374a49301eSmrg
384a49301eSmrgstatic void translate_memcpy_uint( const void *in,
39af69d88dSmrg                                   unsigned start,
4001e04c3fSmrg                                   unsigned in_nr,
4101e04c3fSmrg                                   unsigned out_nr,
4201e04c3fSmrg                                   unsigned restart_index,
434a49301eSmrg                                   void *out )
444a49301eSmrg{
4501e04c3fSmrg   memcpy(out, &((int *)in)[start], out_nr*sizeof(int));
464a49301eSmrg}
477ec681f3Smrg
487ec681f3Smrgstatic void translate_byte_to_ushort( const void *in,
497ec681f3Smrg                                      unsigned start,
507ec681f3Smrg                                      UNUSED unsigned in_nr,
517ec681f3Smrg                                      unsigned out_nr,
527ec681f3Smrg                                      UNUSED unsigned restart_index,
537ec681f3Smrg                                      void *out )
547ec681f3Smrg{
557ec681f3Smrg   uint8_t *src = (uint8_t *)in + start;
567ec681f3Smrg   uint16_t *dst = out;
577ec681f3Smrg   while (out_nr--) {
587ec681f3Smrg      *dst++ = *src++;
597ec681f3Smrg   }
607ec681f3Smrg}
617ec681f3Smrg
627ec681f3Smrgenum pipe_prim_type
637ec681f3Smrgu_index_prim_type_convert(unsigned hw_mask, enum pipe_prim_type prim, bool pv_matches)
647ec681f3Smrg{
657ec681f3Smrg   if ((hw_mask & (1<<prim)) && pv_matches)
667ec681f3Smrg      return prim;
677ec681f3Smrg
687ec681f3Smrg   switch (prim) {
697ec681f3Smrg   case PIPE_PRIM_POINTS:
707ec681f3Smrg      return PIPE_PRIM_POINTS;
717ec681f3Smrg   case PIPE_PRIM_LINES:
727ec681f3Smrg   case PIPE_PRIM_LINE_STRIP:
737ec681f3Smrg   case PIPE_PRIM_LINE_LOOP:
747ec681f3Smrg      return PIPE_PRIM_LINES;
757ec681f3Smrg   case PIPE_PRIM_TRIANGLES:
767ec681f3Smrg   case PIPE_PRIM_TRIANGLE_STRIP:
777ec681f3Smrg   case PIPE_PRIM_TRIANGLE_FAN:
787ec681f3Smrg   case PIPE_PRIM_QUADS:
797ec681f3Smrg   case PIPE_PRIM_QUAD_STRIP:
807ec681f3Smrg   case PIPE_PRIM_POLYGON:
817ec681f3Smrg      return PIPE_PRIM_TRIANGLES;
827ec681f3Smrg   case PIPE_PRIM_LINES_ADJACENCY:
837ec681f3Smrg   case PIPE_PRIM_LINE_STRIP_ADJACENCY:
847ec681f3Smrg      return PIPE_PRIM_LINES_ADJACENCY;
857ec681f3Smrg   case PIPE_PRIM_TRIANGLES_ADJACENCY:
867ec681f3Smrg   case PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY:
877ec681f3Smrg      return PIPE_PRIM_TRIANGLES_ADJACENCY;
887ec681f3Smrg   case PIPE_PRIM_PATCHES:
897ec681f3Smrg      return PIPE_PRIM_PATCHES;
907ec681f3Smrg   default:
917ec681f3Smrg      assert(0);
927ec681f3Smrg      break;
937ec681f3Smrg   }
947ec681f3Smrg   return PIPE_PRIM_POINTS;
957ec681f3Smrg}
964a49301eSmrg
97af69d88dSmrg/**
98af69d88dSmrg * Translate indexes when a driver can't support certain types
99af69d88dSmrg * of drawing.  Example include:
100af69d88dSmrg * - Translate 1-byte indexes into 2-byte indexes
101af69d88dSmrg * - Translate PIPE_PRIM_QUADS into PIPE_PRIM_TRIANGLES when the hardware
102af69d88dSmrg *   doesn't support the former.
103af69d88dSmrg * - Translate from first provoking vertex to last provoking vertex and
104af69d88dSmrg *   vice versa.
105af69d88dSmrg *
10601e04c3fSmrg * Note that this function is used for indexed primitives.
10701e04c3fSmrg *
108af69d88dSmrg * \param hw_mask  mask of (1 << PIPE_PRIM_x) flags indicating which types
109af69d88dSmrg *                 of primitives are supported by the hardware.
110af69d88dSmrg * \param prim  incoming PIPE_PRIM_x
111af69d88dSmrg * \param in_index_size  bytes per index value (1, 2 or 4)
112af69d88dSmrg * \param nr  number of incoming vertices
113af69d88dSmrg * \param in_pv  incoming provoking vertex convention (PV_FIRST or PV_LAST)
114af69d88dSmrg * \param out_pv  desired provoking vertex convention (PV_FIRST or PV_LAST)
11501e04c3fSmrg * \param prim_restart  whether primitive restart is disable or enabled
116af69d88dSmrg * \param out_prim  returns new PIPE_PRIM_x we'll translate to
117af69d88dSmrg * \param out_index_size  returns bytes per new index value (2 or 4)
118af69d88dSmrg * \param out_nr  returns number of new vertices
119af69d88dSmrg * \param out_translate  returns the translation function to use by the caller
120af69d88dSmrg */
12101e04c3fSmrgenum indices_mode
12201e04c3fSmrgu_index_translator(unsigned hw_mask,
12301e04c3fSmrg                   enum pipe_prim_type prim,
12401e04c3fSmrg                   unsigned in_index_size,
12501e04c3fSmrg                   unsigned nr,
12601e04c3fSmrg                   unsigned in_pv,
12701e04c3fSmrg                   unsigned out_pv,
12801e04c3fSmrg                   unsigned prim_restart,
12901e04c3fSmrg                   enum pipe_prim_type *out_prim,
13001e04c3fSmrg                   unsigned *out_index_size,
13101e04c3fSmrg                   unsigned *out_nr,
13201e04c3fSmrg                   u_translate_func *out_translate)
1334a49301eSmrg{
1344a49301eSmrg   unsigned in_idx;
1354a49301eSmrg   unsigned out_idx;
13601e04c3fSmrg   enum indices_mode ret = U_TRANSLATE_NORMAL;
1374a49301eSmrg
138af69d88dSmrg   assert(in_index_size == 1 ||
139af69d88dSmrg          in_index_size == 2 ||
140af69d88dSmrg          in_index_size == 4);
141af69d88dSmrg
1424a49301eSmrg   u_index_init();
1434a49301eSmrg
1444a49301eSmrg   in_idx = in_size_idx(in_index_size);
1457ec681f3Smrg   *out_index_size = u_index_size_convert(in_index_size);
1464a49301eSmrg   out_idx = out_size_idx(*out_index_size);
1474a49301eSmrg
1487ec681f3Smrg   if ((hw_mask & (1<<prim)) &&
1497ec681f3Smrg       in_pv == out_pv)
1504a49301eSmrg   {
1514a49301eSmrg      if (in_index_size == 4)
1524a49301eSmrg         *out_translate = translate_memcpy_uint;
1537ec681f3Smrg      else if (in_index_size == 2)
1544a49301eSmrg         *out_translate = translate_memcpy_ushort;
1557ec681f3Smrg      else
1567ec681f3Smrg         *out_translate = translate_byte_to_ushort;
1574a49301eSmrg
1584a49301eSmrg      *out_prim = prim;
1594a49301eSmrg      *out_nr = nr;
1604a49301eSmrg
1614a49301eSmrg      return U_TRANSLATE_MEMCPY;
1624a49301eSmrg   }
1637ec681f3Smrg   *out_translate = translate[in_idx][out_idx][in_pv][out_pv][prim_restart][prim];
1647ec681f3Smrg   *out_prim = u_index_prim_type_convert(hw_mask, prim, in_pv == out_pv);
1657ec681f3Smrg   *out_nr = u_index_count_converted_indices(hw_mask, in_pv == out_pv, prim, nr);
16601e04c3fSmrg
1677ec681f3Smrg   return ret;
1687ec681f3Smrg}
16901e04c3fSmrg
1707ec681f3Smrgunsigned
1717ec681f3Smrgu_index_count_converted_indices(unsigned hw_mask, bool pv_matches, enum pipe_prim_type prim, unsigned nr)
1727ec681f3Smrg{
1737ec681f3Smrg   if ((hw_mask & (1<<prim)) && pv_matches)
1747ec681f3Smrg      return nr;
1757ec681f3Smrg
1767ec681f3Smrg   switch (prim) {
1777ec681f3Smrg   case PIPE_PRIM_POINTS:
1787ec681f3Smrg   case PIPE_PRIM_PATCHES:
1797ec681f3Smrg      return nr;
1807ec681f3Smrg   case PIPE_PRIM_LINES:
1817ec681f3Smrg      return nr;
1827ec681f3Smrg   case PIPE_PRIM_LINE_STRIP:
1837ec681f3Smrg      return (nr - 1) * 2;
1847ec681f3Smrg   case PIPE_PRIM_LINE_LOOP:
1857ec681f3Smrg      return nr * 2;
1867ec681f3Smrg   case PIPE_PRIM_TRIANGLES:
1877ec681f3Smrg      return nr;
1887ec681f3Smrg   case PIPE_PRIM_TRIANGLE_STRIP:
1897ec681f3Smrg      return (nr - 2) * 3;
1907ec681f3Smrg   case PIPE_PRIM_TRIANGLE_FAN:
1917ec681f3Smrg      return (nr - 2) * 3;
1927ec681f3Smrg   case PIPE_PRIM_QUADS:
1937ec681f3Smrg      return (nr / 4) * 6;
1947ec681f3Smrg   case PIPE_PRIM_QUAD_STRIP:
1957ec681f3Smrg      return (nr - 2) * 3;
1967ec681f3Smrg   case PIPE_PRIM_POLYGON:
1977ec681f3Smrg      return (nr - 2) * 3;
1987ec681f3Smrg   case PIPE_PRIM_LINES_ADJACENCY:
1997ec681f3Smrg      return nr;
2007ec681f3Smrg   case PIPE_PRIM_LINE_STRIP_ADJACENCY:
2017ec681f3Smrg      return (nr - 3) * 4;
2027ec681f3Smrg   case PIPE_PRIM_TRIANGLES_ADJACENCY:
2037ec681f3Smrg      return nr;
2047ec681f3Smrg   case PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY:
2057ec681f3Smrg      return ((nr - 4) / 2) * 6;
2067ec681f3Smrg   default:
2077ec681f3Smrg      assert(0);
2087ec681f3Smrg      break;
2094a49301eSmrg   }
2107ec681f3Smrg   return nr;
2114a49301eSmrg}
2124a49301eSmrg
2134a49301eSmrg
214af69d88dSmrg/**
215af69d88dSmrg * If a driver does not support a particular gallium primitive type
216af69d88dSmrg * (such as PIPE_PRIM_QUAD_STRIP) this function can be used to help
217af69d88dSmrg * convert the primitive into a simpler type (like PIPE_PRIM_TRIANGLES).
218af69d88dSmrg *
219af69d88dSmrg * The generator functions generates a number of ushort or uint indexes
220af69d88dSmrg * for drawing the new type of primitive.
221af69d88dSmrg *
22201e04c3fSmrg * Note that this function is used for non-indexed primitives.
22301e04c3fSmrg *
224af69d88dSmrg * \param hw_mask  a bitmask of (1 << PIPE_PRIM_x) values that indicates
225af69d88dSmrg *                 kind of primitives are supported by the driver.
226af69d88dSmrg * \param prim  the PIPE_PRIM_x that the user wants to draw
227af69d88dSmrg * \param start  index of first vertex to draw
228af69d88dSmrg * \param nr  number of vertices to draw
229af69d88dSmrg * \param in_pv  user's provoking vertex (PV_FIRST/LAST)
230af69d88dSmrg * \param out_pv  desired proking vertex for the hardware (PV_FIRST/LAST)
231af69d88dSmrg * \param out_prim  returns the new primitive type for the driver
232af69d88dSmrg * \param out_index_size  returns OUT_USHORT or OUT_UINT
233af69d88dSmrg * \param out_nr  returns new number of vertices to draw
234af69d88dSmrg * \param out_generate  returns pointer to the generator function
235af69d88dSmrg */
23601e04c3fSmrgenum indices_mode
23701e04c3fSmrgu_index_generator(unsigned hw_mask,
23801e04c3fSmrg                  enum pipe_prim_type prim,
23901e04c3fSmrg                  unsigned start,
24001e04c3fSmrg                  unsigned nr,
24101e04c3fSmrg                  unsigned in_pv,
24201e04c3fSmrg                  unsigned out_pv,
24301e04c3fSmrg                  enum pipe_prim_type *out_prim,
24401e04c3fSmrg                  unsigned *out_index_size,
24501e04c3fSmrg                  unsigned *out_nr,
24601e04c3fSmrg                  u_generate_func *out_generate)
2474a49301eSmrg{
2484a49301eSmrg   unsigned out_idx;
2494a49301eSmrg
2504a49301eSmrg   u_index_init();
2514a49301eSmrg
2524a49301eSmrg   *out_index_size = ((start + nr) > 0xfffe) ? 4 : 2;
2534a49301eSmrg   out_idx = out_size_idx(*out_index_size);
2547ec681f3Smrg   *out_prim = u_index_prim_type_convert(hw_mask, prim, in_pv == out_pv);
2557ec681f3Smrg   *out_nr = u_index_count_converted_indices(hw_mask, in_pv == out_pv, prim, nr);
2564a49301eSmrg
2574a49301eSmrg   if ((hw_mask & (1<<prim)) &&
2584a49301eSmrg       (in_pv == out_pv)) {
2594a49301eSmrg
2604a49301eSmrg      *out_generate = generate[out_idx][in_pv][out_pv][PIPE_PRIM_POINTS];
2614a49301eSmrg      return U_GENERATE_LINEAR;
2624a49301eSmrg   }
2637ec681f3Smrg   *out_generate = generate[out_idx][in_pv][out_pv][prim];
2647ec681f3Smrg   return prim == PIPE_PRIM_LINE_LOOP ? U_GENERATE_ONE_OFF : U_GENERATE_REUSABLE;
2654a49301eSmrg}
266