move util/indices to core util

these are useful tools to have outside of gallium

Reviewed-by: Jesse Natalie <jenatali@microsoft.com>
Reviewed-by: Pierre-Eric Pelloux-Prayer <pierre-eric.pelloux-prayer@amd.com>

Reviewed-by: Adam Jackson <ajax@redhat.com>
Acked-by: Marek Olšák <marek.olsak@amd.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/13741>
This commit is contained in:
Mike Blumenkrantz
2021-11-10 09:57:48 -05:00
committed by Marge Bot
parent 88e4d3809c
commit 97ba2f2fd4
10 changed files with 22 additions and 22 deletions
+265
View File
@@ -0,0 +1,265 @@
/*
* Copyright 2009 VMware, Inc.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* on the rights to use, copy, modify, merge, publish, distribute, sub
* license, and/or sell copies of the Software, and to permit persons to whom
* the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* VMWARE AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "u_indices.h"
#include "u_indices_priv.h"
static void translate_memcpy_ushort( const void *in,
unsigned start,
unsigned in_nr,
unsigned out_nr,
unsigned restart_index,
void *out )
{
memcpy(out, &((short *)in)[start], out_nr*sizeof(short));
}
static void translate_memcpy_uint( const void *in,
unsigned start,
unsigned in_nr,
unsigned out_nr,
unsigned restart_index,
void *out )
{
memcpy(out, &((int *)in)[start], out_nr*sizeof(int));
}
static void translate_byte_to_ushort( const void *in,
unsigned start,
UNUSED unsigned in_nr,
unsigned out_nr,
UNUSED unsigned restart_index,
void *out )
{
uint8_t *src = (uint8_t *)in + start;
uint16_t *dst = out;
while (out_nr--) {
*dst++ = *src++;
}
}
enum pipe_prim_type
u_index_prim_type_convert(unsigned hw_mask, enum pipe_prim_type prim, bool pv_matches)
{
if ((hw_mask & (1<<prim)) && pv_matches)
return prim;
switch (prim) {
case PIPE_PRIM_POINTS:
return PIPE_PRIM_POINTS;
case PIPE_PRIM_LINES:
case PIPE_PRIM_LINE_STRIP:
case PIPE_PRIM_LINE_LOOP:
return PIPE_PRIM_LINES;
case PIPE_PRIM_TRIANGLES:
case PIPE_PRIM_TRIANGLE_STRIP:
case PIPE_PRIM_TRIANGLE_FAN:
case PIPE_PRIM_QUADS:
case PIPE_PRIM_QUAD_STRIP:
case PIPE_PRIM_POLYGON:
return PIPE_PRIM_TRIANGLES;
case PIPE_PRIM_LINES_ADJACENCY:
case PIPE_PRIM_LINE_STRIP_ADJACENCY:
return PIPE_PRIM_LINES_ADJACENCY;
case PIPE_PRIM_TRIANGLES_ADJACENCY:
case PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY:
return PIPE_PRIM_TRIANGLES_ADJACENCY;
case PIPE_PRIM_PATCHES:
return PIPE_PRIM_PATCHES;
default:
assert(0);
break;
}
return PIPE_PRIM_POINTS;
}
/**
* Translate indexes when a driver can't support certain types
* of drawing. Example include:
* - Translate 1-byte indexes into 2-byte indexes
* - Translate PIPE_PRIM_QUADS into PIPE_PRIM_TRIANGLES when the hardware
* doesn't support the former.
* - Translate from first provoking vertex to last provoking vertex and
* vice versa.
*
* Note that this function is used for indexed primitives.
*
* \param hw_mask mask of (1 << PIPE_PRIM_x) flags indicating which types
* of primitives are supported by the hardware.
* \param prim incoming PIPE_PRIM_x
* \param in_index_size bytes per index value (1, 2 or 4)
* \param nr number of incoming vertices
* \param in_pv incoming provoking vertex convention (PV_FIRST or PV_LAST)
* \param out_pv desired provoking vertex convention (PV_FIRST or PV_LAST)
* \param prim_restart whether primitive restart is disable or enabled
* \param out_prim returns new PIPE_PRIM_x we'll translate to
* \param out_index_size returns bytes per new index value (2 or 4)
* \param out_nr returns number of new vertices
* \param out_translate returns the translation function to use by the caller
*/
enum indices_mode
u_index_translator(unsigned hw_mask,
enum pipe_prim_type prim,
unsigned in_index_size,
unsigned nr,
unsigned in_pv,
unsigned out_pv,
unsigned prim_restart,
enum pipe_prim_type *out_prim,
unsigned *out_index_size,
unsigned *out_nr,
u_translate_func *out_translate)
{
unsigned in_idx;
unsigned out_idx;
enum indices_mode ret = U_TRANSLATE_NORMAL;
assert(in_index_size == 1 ||
in_index_size == 2 ||
in_index_size == 4);
u_index_init();
in_idx = in_size_idx(in_index_size);
*out_index_size = u_index_size_convert(in_index_size);
out_idx = out_size_idx(*out_index_size);
if ((hw_mask & (1<<prim)) &&
in_pv == out_pv)
{
if (in_index_size == 4)
*out_translate = translate_memcpy_uint;
else if (in_index_size == 2)
*out_translate = translate_memcpy_ushort;
else
*out_translate = translate_byte_to_ushort;
*out_prim = prim;
*out_nr = nr;
return U_TRANSLATE_MEMCPY;
}
*out_translate = translate[in_idx][out_idx][in_pv][out_pv][prim_restart][prim];
*out_prim = u_index_prim_type_convert(hw_mask, prim, in_pv == out_pv);
*out_nr = u_index_count_converted_indices(hw_mask, in_pv == out_pv, prim, nr);
return ret;
}
unsigned
u_index_count_converted_indices(unsigned hw_mask, bool pv_matches, enum pipe_prim_type prim, unsigned nr)
{
if ((hw_mask & (1<<prim)) && pv_matches)
return nr;
switch (prim) {
case PIPE_PRIM_POINTS:
case PIPE_PRIM_PATCHES:
return nr;
case PIPE_PRIM_LINES:
return nr;
case PIPE_PRIM_LINE_STRIP:
return (nr - 1) * 2;
case PIPE_PRIM_LINE_LOOP:
return nr * 2;
case PIPE_PRIM_TRIANGLES:
return nr;
case PIPE_PRIM_TRIANGLE_STRIP:
return (nr - 2) * 3;
case PIPE_PRIM_TRIANGLE_FAN:
return (nr - 2) * 3;
case PIPE_PRIM_QUADS:
return (nr / 4) * 6;
case PIPE_PRIM_QUAD_STRIP:
return (nr - 2) * 3;
case PIPE_PRIM_POLYGON:
return (nr - 2) * 3;
case PIPE_PRIM_LINES_ADJACENCY:
return nr;
case PIPE_PRIM_LINE_STRIP_ADJACENCY:
return (nr - 3) * 4;
case PIPE_PRIM_TRIANGLES_ADJACENCY:
return nr;
case PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY:
return ((nr - 4) / 2) * 6;
default:
assert(0);
break;
}
return nr;
}
/**
* If a driver does not support a particular gallium primitive type
* (such as PIPE_PRIM_QUAD_STRIP) this function can be used to help
* convert the primitive into a simpler type (like PIPE_PRIM_TRIANGLES).
*
* The generator functions generates a number of ushort or uint indexes
* for drawing the new type of primitive.
*
* Note that this function is used for non-indexed primitives.
*
* \param hw_mask a bitmask of (1 << PIPE_PRIM_x) values that indicates
* kind of primitives are supported by the driver.
* \param prim the PIPE_PRIM_x that the user wants to draw
* \param start index of first vertex to draw
* \param nr number of vertices to draw
* \param in_pv user's provoking vertex (PV_FIRST/LAST)
* \param out_pv desired proking vertex for the hardware (PV_FIRST/LAST)
* \param out_prim returns the new primitive type for the driver
* \param out_index_size returns OUT_USHORT or OUT_UINT
* \param out_nr returns new number of vertices to draw
* \param out_generate returns pointer to the generator function
*/
enum indices_mode
u_index_generator(unsigned hw_mask,
enum pipe_prim_type prim,
unsigned start,
unsigned nr,
unsigned in_pv,
unsigned out_pv,
enum pipe_prim_type *out_prim,
unsigned *out_index_size,
unsigned *out_nr,
u_generate_func *out_generate)
{
unsigned out_idx;
u_index_init();
*out_index_size = ((start + nr) > 0xfffe) ? 4 : 2;
out_idx = out_size_idx(*out_index_size);
*out_prim = u_index_prim_type_convert(hw_mask, prim, in_pv == out_pv);
*out_nr = u_index_count_converted_indices(hw_mask, in_pv == out_pv, prim, nr);
if ((hw_mask & (1<<prim)) &&
(in_pv == out_pv)) {
*out_generate = generate[out_idx][in_pv][out_pv][PIPE_PRIM_POINTS];
return U_GENERATE_LINEAR;
}
*out_generate = generate[out_idx][in_pv][out_pv][prim];
return prim == PIPE_PRIM_LINE_LOOP ? U_GENERATE_ONE_OFF : U_GENERATE_REUSABLE;
}
+173
View File
@@ -0,0 +1,173 @@
/*
* Copyright 2009 VMware, Inc.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* on the rights to use, copy, modify, merge, publish, distribute, sub
* license, and/or sell copies of the Software, and to permit persons to whom
* the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* VMWARE AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef U_INDICES_H
#define U_INDICES_H
#include "pipe/p_compiler.h"
#include "pipe/p_defines.h"
/* First/last provoking vertex */
#define PV_FIRST 0
#define PV_LAST 1
#define PV_COUNT 2
/* primitive restart disable/enable flags */
#define PR_DISABLE 0
#define PR_ENABLE 1
#define PR_COUNT 2
/**
* Index translator function (for glDrawElements() case)
*
* \param in the input index buffer
* \param start the index of the first vertex (pipe_draw_info::start)
* \param nr the number of vertices (pipe_draw_info::count)
* \param out output buffer big enough for nr vertices (of
* @out_index_size bytes each)
*/
typedef void (*u_translate_func)( const void *in,
unsigned start,
unsigned in_nr,
unsigned out_nr,
unsigned restart_index,
void *out );
/**
* Index generator function (for glDrawArrays() case)
*
* \param start the index of the first vertex (pipe_draw_info::start)
* \param nr the number of vertices (pipe_draw_info::count)
* \param out output buffer big enough for nr vertices (of
* @out_index_size bytes each)
*/
typedef void (*u_generate_func)( unsigned start,
unsigned nr,
void *out );
/* Return codes describe the translate/generate operation. Caller may
* be able to reuse translated indices under some circumstances.
*/
enum indices_mode {
U_TRANSLATE_ERROR = -1,
U_TRANSLATE_NORMAL = 1,
U_TRANSLATE_MEMCPY = 2,
U_GENERATE_LINEAR = 3,
U_GENERATE_REUSABLE= 4,
U_GENERATE_ONE_OFF = 5,
};
void u_index_init( void );
/* returns the primitive type resulting from index translation */
enum pipe_prim_type
u_index_prim_type_convert(unsigned hw_mask, enum pipe_prim_type prim, bool pv_matches);
static inline unsigned
u_index_size_convert(unsigned index_size)
{
return (index_size == 4) ? 4 : 2;
}
unsigned
u_index_count_converted_indices(unsigned hw_mask, bool pv_matches, enum pipe_prim_type prim, unsigned nr);
/**
* For indexed drawing, this function determines what kind of primitive
* transformation is needed (if any) for handling:
* - unsupported primitive types (such as PIPE_PRIM_POLYGON)
* - changing the provoking vertex
* - primitive restart
* - index size (1 byte, 2 byte or 4 byte indexes)
*/
enum indices_mode
u_index_translator(unsigned hw_mask,
enum pipe_prim_type prim,
unsigned in_index_size,
unsigned nr,
unsigned in_pv, /* API */
unsigned out_pv, /* hardware */
unsigned prim_restart,
enum pipe_prim_type *out_prim,
unsigned *out_index_size,
unsigned *out_nr,
u_translate_func *out_translate);
/**
* For non-indexed drawing, this function determines what kind of primitive
* transformation is needed (see above).
*
* Note that even when generating it is necessary to know what the
* API's PV is, as the indices generated will depend on whether it is
* the same as hardware or not, and in the case of triangle strips,
* whether it is first or last.
*/
enum indices_mode
u_index_generator(unsigned hw_mask,
enum pipe_prim_type prim,
unsigned start,
unsigned nr,
unsigned in_pv, /* API */
unsigned out_pv, /* hardware */
enum pipe_prim_type *out_prim,
unsigned *out_index_size,
unsigned *out_nr,
u_generate_func *out_generate);
void u_unfilled_init( void );
/**
* If the driver can't handle "unfilled" primitives (i.e. drawing triangle
* primitives as 3 lines or 3 points) this function can be used to translate
* an indexed primitive into a new indexed primitive to draw as lines or
* points.
*/
enum indices_mode
u_unfilled_translator(enum pipe_prim_type prim,
unsigned in_index_size,
unsigned nr,
unsigned unfilled_mode,
enum pipe_prim_type *out_prim,
unsigned *out_index_size,
unsigned *out_nr,
u_translate_func *out_translate);
/**
* As above, but for non-indexed (array) primitives.
*/
enum indices_mode
u_unfilled_generator(enum pipe_prim_type prim,
unsigned start,
unsigned nr,
unsigned unfilled_mode,
enum pipe_prim_type *out_prim,
unsigned *out_index_size,
unsigned *out_nr,
u_generate_func *out_generate);
#endif
+462
View File
@@ -0,0 +1,462 @@
copyright = '''
/*
* Copyright 2009 VMware, Inc.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* on the rights to use, copy, modify, merge, publish, distribute, sub
* license, and/or sell copies of the Software, and to permit persons to whom
* the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* VMWARE AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
'''
GENERATE, UBYTE, USHORT, UINT = 'generate', 'ubyte', 'ushort', 'uint'
FIRST, LAST = 'first', 'last'
PRDISABLE, PRENABLE = 'prdisable', 'prenable'
INTYPES = (GENERATE, UBYTE, USHORT, UINT)
OUTTYPES = (USHORT, UINT)
PVS=(FIRST, LAST)
PRS=(PRDISABLE, PRENABLE)
PRIMS=('points',
'lines',
'linestrip',
'lineloop',
'tris',
'trifan',
'tristrip',
'quads',
'quadstrip',
'polygon',
'linesadj',
'linestripadj',
'trisadj',
'tristripadj')
LONGPRIMS=('PIPE_PRIM_POINTS',
'PIPE_PRIM_LINES',
'PIPE_PRIM_LINE_STRIP',
'PIPE_PRIM_LINE_LOOP',
'PIPE_PRIM_TRIANGLES',
'PIPE_PRIM_TRIANGLE_FAN',
'PIPE_PRIM_TRIANGLE_STRIP',
'PIPE_PRIM_QUADS',
'PIPE_PRIM_QUAD_STRIP',
'PIPE_PRIM_POLYGON',
'PIPE_PRIM_LINES_ADJACENCY',
'PIPE_PRIM_LINE_STRIP_ADJACENCY',
'PIPE_PRIM_TRIANGLES_ADJACENCY',
'PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY')
longprim = dict(zip(PRIMS, LONGPRIMS))
intype_idx = dict(ubyte='IN_UBYTE', ushort='IN_USHORT', uint='IN_UINT')
outtype_idx = dict(ushort='OUT_USHORT', uint='OUT_UINT')
pv_idx = dict(first='PV_FIRST', last='PV_LAST')
pr_idx = dict(prdisable='PR_DISABLE', prenable='PR_ENABLE')
def prolog():
print('''/* File automatically generated by u_indices_gen.py */''')
print(copyright)
print(r'''
/**
* @file
* Functions to translate and generate index lists
*/
#include "indices/u_indices_priv.h"
#include "util/u_debug.h"
#include "util/u_memory.h"
static unsigned out_size_idx( unsigned index_size )
{
switch (index_size) {
case 4: return OUT_UINT;
case 2: return OUT_USHORT;
default: assert(0); return OUT_USHORT;
}
}
static unsigned in_size_idx( unsigned index_size )
{
switch (index_size) {
case 4: return IN_UINT;
case 2: return IN_USHORT;
case 1: return IN_UBYTE;
default: assert(0); return IN_UBYTE;
}
}
static u_translate_func translate[IN_COUNT][OUT_COUNT][PV_COUNT][PV_COUNT][PR_COUNT][PRIM_COUNT];
static u_generate_func generate[OUT_COUNT][PV_COUNT][PV_COUNT][PRIM_COUNT];
''')
def vert( intype, outtype, v0 ):
if intype == GENERATE:
return '(' + outtype + ')(' + v0 + ')'
else:
return '(' + outtype + ')in[' + v0 + ']'
def point( intype, outtype, ptr, v0 ):
print(' (' + ptr + ')[0] = ' + vert( intype, outtype, v0 ) + ';')
def line( intype, outtype, ptr, v0, v1 ):
print(' (' + ptr + ')[0] = ' + vert( intype, outtype, v0 ) + ';')
print(' (' + ptr + ')[1] = ' + vert( intype, outtype, v1 ) + ';')
def tri( intype, outtype, ptr, v0, v1, v2 ):
print(' (' + ptr + ')[0] = ' + vert( intype, outtype, v0 ) + ';')
print(' (' + ptr + ')[1] = ' + vert( intype, outtype, v1 ) + ';')
print(' (' + ptr + ')[2] = ' + vert( intype, outtype, v2 ) + ';')
def lineadj( intype, outtype, ptr, v0, v1, v2, v3 ):
print(' (' + ptr + ')[0] = ' + vert( intype, outtype, v0 ) + ';')
print(' (' + ptr + ')[1] = ' + vert( intype, outtype, v1 ) + ';')
print(' (' + ptr + ')[2] = ' + vert( intype, outtype, v2 ) + ';')
print(' (' + ptr + ')[3] = ' + vert( intype, outtype, v3 ) + ';')
def triadj( intype, outtype, ptr, v0, v1, v2, v3, v4, v5 ):
print(' (' + ptr + ')[0] = ' + vert( intype, outtype, v0 ) + ';')
print(' (' + ptr + ')[1] = ' + vert( intype, outtype, v1 ) + ';')
print(' (' + ptr + ')[2] = ' + vert( intype, outtype, v2 ) + ';')
print(' (' + ptr + ')[3] = ' + vert( intype, outtype, v3 ) + ';')
print(' (' + ptr + ')[4] = ' + vert( intype, outtype, v4 ) + ';')
print(' (' + ptr + ')[5] = ' + vert( intype, outtype, v5 ) + ';')
def do_point( intype, outtype, ptr, v0 ):
point( intype, outtype, ptr, v0 )
def do_line( intype, outtype, ptr, v0, v1, inpv, outpv ):
if inpv == outpv:
line( intype, outtype, ptr, v0, v1 )
else:
line( intype, outtype, ptr, v1, v0 )
def do_tri( intype, outtype, ptr, v0, v1, v2, inpv, outpv ):
if inpv == outpv:
tri( intype, outtype, ptr, v0, v1, v2 )
else:
if inpv == FIRST:
tri( intype, outtype, ptr, v1, v2, v0 )
else:
tri( intype, outtype, ptr, v2, v0, v1 )
def do_quad( intype, outtype, ptr, v0, v1, v2, v3, inpv, outpv ):
if inpv == LAST:
do_tri( intype, outtype, ptr+'+0', v0, v1, v3, inpv, outpv );
do_tri( intype, outtype, ptr+'+3', v1, v2, v3, inpv, outpv );
else:
do_tri( intype, outtype, ptr+'+0', v0, v1, v2, inpv, outpv );
do_tri( intype, outtype, ptr+'+3', v0, v2, v3, inpv, outpv );
def do_lineadj( intype, outtype, ptr, v0, v1, v2, v3, inpv, outpv ):
if inpv == outpv:
lineadj( intype, outtype, ptr, v0, v1, v2, v3 )
else:
lineadj( intype, outtype, ptr, v3, v2, v1, v0 )
def do_triadj( intype, outtype, ptr, v0, v1, v2, v3, v4, v5, inpv, outpv ):
if inpv == outpv:
triadj( intype, outtype, ptr, v0, v1, v2, v3, v4, v5 )
else:
triadj( intype, outtype, ptr, v4, v5, v0, v1, v2, v3 )
def name(intype, outtype, inpv, outpv, pr, prim):
if intype == GENERATE:
return 'generate_' + prim + '_' + outtype + '_' + inpv + '2' + outpv
else:
return 'translate_' + prim + '_' + intype + '2' + outtype + '_' + inpv + '2' + outpv + '_' + pr
def preamble(intype, outtype, inpv, outpv, pr, prim):
print('static void ' + name( intype, outtype, inpv, outpv, pr, prim ) + '(')
if intype != GENERATE:
print(' const void * restrict _in,')
print(' unsigned start,')
if intype != GENERATE:
print(' unsigned in_nr,')
print(' unsigned out_nr,')
if intype != GENERATE:
print(' unsigned restart_index,')
print(' void * restrict _out )')
print('{')
if intype != GENERATE:
print(' const ' + intype + '* restrict in = (const ' + intype + '* restrict)_in;')
print(' ' + outtype + ' * restrict out = (' + outtype + '* restrict)_out;')
print(' unsigned i, j;')
print(' (void)j;')
def postamble():
print('}')
def prim_restart(in_verts, out_verts, out_prims, close_func = None):
print('restart:')
print(' if (i + ' + str(in_verts) + ' > in_nr) {')
for i in range(out_prims):
for j in range(out_verts):
print(' (out+j+' + str(out_verts * i) + ')[' + str(j) + '] = restart_index;')
print(' continue;')
print(' }')
for i in range(in_verts):
print(' if (in[i + ' + str(i) + '] == restart_index) {')
print(' i += ' + str(i + 1) + ';')
if close_func is not None:
close_func(i)
print(' goto restart;')
print(' }')
def points(intype, outtype, inpv, outpv, pr):
preamble(intype, outtype, inpv, outpv, pr, prim='points')
print(' for (i = start, j = 0; j < out_nr; j++, i++) { ')
do_point( intype, outtype, 'out+j', 'i' );
print(' }')
postamble()
def lines(intype, outtype, inpv, outpv, pr):
preamble(intype, outtype, inpv, outpv, pr, prim='lines')
print(' for (i = start, j = 0; j < out_nr; j+=2, i+=2) { ')
do_line( intype, outtype, 'out+j', 'i', 'i+1', inpv, outpv );
print(' }')
postamble()
def linestrip(intype, outtype, inpv, outpv, pr):
preamble(intype, outtype, inpv, outpv, pr, prim='linestrip')
print(' for (i = start, j = 0; j < out_nr; j+=2, i++) { ')
do_line( intype, outtype, 'out+j', 'i', 'i+1', inpv, outpv );
print(' }')
postamble()
def lineloop(intype, outtype, inpv, outpv, pr):
preamble(intype, outtype, inpv, outpv, pr, prim='lineloop')
print(' unsigned end = start;')
print(' for (i = start, j = 0; j < out_nr - 2; j+=2, i++) { ')
if pr == PRENABLE:
def close_func(index):
do_line( intype, outtype, 'out+j', 'end', 'start', inpv, outpv )
print(' start = i;')
print(' end = start;')
print(' j += 2;')
prim_restart(2, 2, 1, close_func)
do_line( intype, outtype, 'out+j', 'i', 'i+1', inpv, outpv );
print(' end = i+1;')
print(' }')
do_line( intype, outtype, 'out+j', 'end', 'start', inpv, outpv );
postamble()
def tris(intype, outtype, inpv, outpv, pr):
preamble(intype, outtype, inpv, outpv, pr, prim='tris')
print(' for (i = start, j = 0; j < out_nr; j+=3, i+=3) { ')
do_tri( intype, outtype, 'out+j', 'i', 'i+1', 'i+2', inpv, outpv );
print(' }')
postamble()
def tristrip(intype, outtype, inpv, outpv, pr):
preamble(intype, outtype, inpv, outpv, pr, prim='tristrip')
print(' for (i = start, j = 0; j < out_nr; j+=3, i++) { ')
if inpv == FIRST:
do_tri( intype, outtype, 'out+j', 'i', 'i+1+(i&1)', 'i+2-(i&1)', inpv, outpv );
else:
do_tri( intype, outtype, 'out+j', 'i+(i&1)', 'i+1-(i&1)', 'i+2', inpv, outpv );
print(' }')
postamble()
def trifan(intype, outtype, inpv, outpv, pr):
preamble(intype, outtype, inpv, outpv, pr, prim='trifan')
print(' for (i = start, j = 0; j < out_nr; j+=3, i++) { ')
if pr == PRENABLE:
def close_func(index):
print(' start = i;')
prim_restart(3, 3, 1, close_func)
if inpv == FIRST:
do_tri( intype, outtype, 'out+j', 'i+1', 'i+2', 'start', inpv, outpv );
else:
do_tri( intype, outtype, 'out+j', 'start', 'i+1', 'i+2', inpv, outpv );
print(' }')
postamble()
def polygon(intype, outtype, inpv, outpv, pr):
preamble(intype, outtype, inpv, outpv, pr, prim='polygon')
print(' for (i = start, j = 0; j < out_nr; j+=3, i++) { ')
if pr == PRENABLE:
def close_func(index):
print(' start = i;')
prim_restart(3, 3, 1, close_func)
if inpv == FIRST:
do_tri( intype, outtype, 'out+j', 'start', 'i+1', 'i+2', inpv, outpv );
else:
do_tri( intype, outtype, 'out+j', 'i+1', 'i+2', 'start', inpv, outpv );
print(' }')
postamble()
def quads(intype, outtype, inpv, outpv, pr):
preamble(intype, outtype, inpv, outpv, pr, prim='quads')
print(' for (i = start, j = 0; j < out_nr; j+=6, i+=4) { ')
if pr == PRENABLE:
prim_restart(4, 3, 2)
do_quad( intype, outtype, 'out+j', 'i+0', 'i+1', 'i+2', 'i+3', inpv, outpv );
print(' }')
postamble()
def quadstrip(intype, outtype, inpv, outpv, pr):
preamble(intype, outtype, inpv, outpv, pr, prim='quadstrip')
print(' for (i = start, j = 0; j < out_nr; j+=6, i+=2) { ')
if pr == PRENABLE:
prim_restart(4, 3, 2)
if inpv == LAST:
do_quad( intype, outtype, 'out+j', 'i+2', 'i+0', 'i+1', 'i+3', inpv, outpv );
else:
do_quad( intype, outtype, 'out+j', 'i+0', 'i+1', 'i+3', 'i+2', inpv, outpv );
print(' }')
postamble()
def linesadj(intype, outtype, inpv, outpv, pr):
preamble(intype, outtype, inpv, outpv, pr, prim='linesadj')
print(' for (i = start, j = 0; j < out_nr; j+=4, i+=4) { ')
do_lineadj( intype, outtype, 'out+j', 'i+0', 'i+1', 'i+2', 'i+3', inpv, outpv )
print(' }')
postamble()
def linestripadj(intype, outtype, inpv, outpv, pr):
preamble(intype, outtype, inpv, outpv, pr, prim='linestripadj')
print(' for (i = start, j = 0; j < out_nr; j+=4, i++) {')
do_lineadj( intype, outtype, 'out+j', 'i+0', 'i+1', 'i+2', 'i+3', inpv, outpv )
print(' }')
postamble()
def trisadj(intype, outtype, inpv, outpv, pr):
preamble(intype, outtype, inpv, outpv, pr, prim='trisadj')
print(' for (i = start, j = 0; j < out_nr; j+=6, i+=6) { ')
do_triadj( intype, outtype, 'out+j', 'i+0', 'i+1', 'i+2', 'i+3',
'i+4', 'i+5', inpv, outpv )
print(' }')
postamble()
def tristripadj(intype, outtype, inpv, outpv, pr):
preamble(intype, outtype, inpv, outpv, pr, prim='tristripadj')
print(' for (i = start, j = 0; j < out_nr; i+=2, j+=6) { ')
print(' if (i % 4 == 0) {')
print(' /* even triangle */')
do_triadj( intype, outtype, 'out+j',
'i+0', 'i+1', 'i+2', 'i+3', 'i+4', 'i+5', inpv, outpv )
print(' } else {')
print(' /* odd triangle */')
do_triadj( intype, outtype, 'out+j',
'i+2', 'i-2', 'i+0', 'i+3', 'i+4', 'i+6', inpv, outpv )
print(' }')
print(' }')
postamble()
def emit_funcs():
for intype in INTYPES:
for outtype in OUTTYPES:
for inpv in (FIRST, LAST):
for outpv in (FIRST, LAST):
for pr in (PRDISABLE, PRENABLE):
if pr == PRENABLE and intype == GENERATE:
continue
points(intype, outtype, inpv, outpv, pr)
lines(intype, outtype, inpv, outpv, pr)
linestrip(intype, outtype, inpv, outpv, pr)
lineloop(intype, outtype, inpv, outpv, pr)
tris(intype, outtype, inpv, outpv, pr)
tristrip(intype, outtype, inpv, outpv, pr)
trifan(intype, outtype, inpv, outpv, pr)
quads(intype, outtype, inpv, outpv, pr)
quadstrip(intype, outtype, inpv, outpv, pr)
polygon(intype, outtype, inpv, outpv, pr)
linesadj(intype, outtype, inpv, outpv, pr)
linestripadj(intype, outtype, inpv, outpv, pr)
trisadj(intype, outtype, inpv, outpv, pr)
tristripadj(intype, outtype, inpv, outpv, pr)
def init(intype, outtype, inpv, outpv, pr, prim):
if intype == GENERATE:
print ('generate[' +
outtype_idx[outtype] +
'][' + pv_idx[inpv] +
'][' + pv_idx[outpv] +
'][' + longprim[prim] +
'] = ' + name( intype, outtype, inpv, outpv, pr, prim ) + ';')
else:
print ('translate[' +
intype_idx[intype] +
'][' + outtype_idx[outtype] +
'][' + pv_idx[inpv] +
'][' + pv_idx[outpv] +
'][' + pr_idx[pr] +
'][' + longprim[prim] +
'] = ' + name( intype, outtype, inpv, outpv, pr, prim ) + ';')
def emit_all_inits():
for intype in INTYPES:
for outtype in OUTTYPES:
for inpv in PVS:
for outpv in PVS:
for pr in PRS:
for prim in PRIMS:
init(intype, outtype, inpv, outpv, pr, prim)
def emit_init():
print('void u_index_init( void )')
print('{')
print(' static int firsttime = 1;')
print(' if (!firsttime) return;')
print(' firsttime = 0;')
emit_all_inits()
print('}')
def epilog():
print('#include "indices/u_indices.c"')
def main():
prolog()
emit_funcs()
emit_init()
epilog()
if __name__ == '__main__':
main()
+43
View File
@@ -0,0 +1,43 @@
/*
* Copyright 2009 VMware, Inc.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* on the rights to use, copy, modify, merge, publish, distribute, sub
* license, and/or sell copies of the Software, and to permit persons to whom
* the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* VMWARE AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef U_INDICES_PRIV_H
#define U_INDICES_PRIV_H
#include "pipe/p_compiler.h"
#include "u_indices.h"
#define IN_UBYTE 0
#define IN_USHORT 1
#define IN_UINT 2
#define IN_COUNT 3
#define OUT_USHORT 0
#define OUT_UINT 1
#define OUT_COUNT 2
#define PRIM_COUNT (PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY + 1)
#endif
+359
View File
@@ -0,0 +1,359 @@
/*
* Copyright (C) 2013 Rob Clark <robclark@freedesktop.org>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Authors:
* Rob Clark <robclark@freedesktop.org>
*/
/**
* This module converts provides a more convenient front-end to u_indices,
* etc, utils to convert primitive types supported not supported by the
* hardware. It handles binding new index buffer state, and restoring
* previous state after. To use, put something like this at the front of
* drivers pipe->draw_vbo():
*
* // emulate unsupported primitives:
* if (info->mode needs emulating) {
* util_primconvert_save_rasterizer_state(ctx->primconvert, ctx->rasterizer);
* util_primconvert_draw_vbo(ctx->primconvert, info);
* return;
* }
*
*/
#include "pipe/p_state.h"
#include "util/u_draw.h"
#include "util/u_inlines.h"
#include "util/u_memory.h"
#include "util/u_prim.h"
#include "util/u_prim_restart.h"
#include "util/u_upload_mgr.h"
#include "indices/u_indices.h"
#include "indices/u_primconvert.h"
struct primconvert_context
{
struct pipe_context *pipe;
struct primconvert_config cfg;
unsigned api_pv;
};
struct primconvert_context *
util_primconvert_create_config(struct pipe_context *pipe,
struct primconvert_config *cfg)
{
struct primconvert_context *pc = CALLOC_STRUCT(primconvert_context);
if (!pc)
return NULL;
pc->pipe = pipe;
pc->cfg = *cfg;
return pc;
}
struct primconvert_context *
util_primconvert_create(struct pipe_context *pipe, uint32_t primtypes_mask)
{
struct primconvert_config cfg = { .primtypes_mask = primtypes_mask, .restart_primtypes_mask = primtypes_mask };
return util_primconvert_create_config(pipe, &cfg);
}
void
util_primconvert_destroy(struct primconvert_context *pc)
{
FREE(pc);
}
void
util_primconvert_save_rasterizer_state(struct primconvert_context *pc,
const struct pipe_rasterizer_state
*rast)
{
util_primconvert_save_flatshade_first(pc, rast->flatshade_first);
}
void
util_primconvert_save_flatshade_first(struct primconvert_context *pc, bool flatshade_first)
{
/* if we actually translated the provoking vertex for the buffer,
* we would actually need to save/restore rasterizer state. As
* it is, we just need to make note of the pv.
*/
pc->api_pv = flatshade_first ? PV_FIRST : PV_LAST;
}
static bool
primconvert_init_draw(struct primconvert_context *pc,
const struct pipe_draw_info *info,
const struct pipe_draw_indirect_info *indirect,
const struct pipe_draw_start_count_bias *draws,
struct pipe_draw_info *new_info,
struct pipe_draw_start_count_bias *new_draw)
{
struct pipe_draw_start_count_bias *direct_draws = NULL;
unsigned num_direct_draws = 0;
struct pipe_transfer *src_transfer = NULL;
u_translate_func trans_func, direct_draw_func;
u_generate_func gen_func;
const void *src = NULL;
void *dst;
unsigned ib_offset;
unsigned total_index_count = draws->count;
void *rewrite_buffer = NULL;
const struct pipe_draw_start_count_bias *draw = &draws[0];
/* Filter out degenerate primitives, u_upload_alloc() will assert
* on size==0 so just bail:
*/
if (!info->primitive_restart &&
!u_trim_pipe_prim(info->mode, (unsigned*)&draw->count))
return false;
util_draw_init_info(new_info);
new_info->index_bounds_valid = info->index_bounds_valid;
new_info->min_index = info->min_index;
new_info->max_index = info->max_index;
new_info->start_instance = info->start_instance;
new_info->instance_count = info->instance_count;
new_info->primitive_restart = info->primitive_restart;
new_info->restart_index = info->restart_index;
if (info->index_size) {
enum pipe_prim_type mode = new_info->mode = u_index_prim_type_convert(pc->cfg.primtypes_mask, info->mode, true);
unsigned index_size = info->index_size;
new_info->index_size = u_index_size_convert(info->index_size);
src = info->has_user_indices ? info->index.user : NULL;
if (!src) {
src = pipe_buffer_map(pc->pipe, info->index.resource,
PIPE_MAP_READ, &src_transfer);
}
src = (const uint8_t *)src;
/* if the resulting primitive type is not supported by the driver for primitive restart,
* or if the original primitive type was not supported by the driver,
* the draw needs to be rewritten to not use primitive restart
*/
if (info->primitive_restart &&
(!(pc->cfg.restart_primtypes_mask & BITFIELD_BIT(mode)) ||
!(pc->cfg.primtypes_mask & BITFIELD_BIT(info->mode)))) {
/* step 1: rewrite draw to not use primitive primitive restart;
* this pre-filters degenerate primitives
*/
direct_draws = util_prim_restart_convert_to_direct(src, info, draw, &num_direct_draws,
&new_info->min_index, &new_info->max_index, &total_index_count);
new_info->primitive_restart = false;
/* step 2: get a translator function which does nothing but handle any index size conversions
* which may or may not occur (8bit -> 16bit)
*/
u_index_translator(0xffff,
info->mode, index_size, total_index_count,
pc->api_pv, pc->api_pv,
PR_DISABLE,
&mode, &index_size, &new_draw->count,
&direct_draw_func);
/* this should always be a direct translation */
assert(new_draw->count == total_index_count);
/* step 3: allocate a temp buffer for an intermediate rewrite step
* if no indices were found, this was a single incomplete restart and can be discarded
*/
if (total_index_count)
rewrite_buffer = malloc(index_size * total_index_count);
if (!rewrite_buffer) {
if (src_transfer)
pipe_buffer_unmap(pc->pipe, src_transfer);
return false;
}
}
/* (step 4: get the actual primitive conversion translator function) */
u_index_translator(pc->cfg.primtypes_mask,
info->mode, index_size, total_index_count,
pc->api_pv, pc->api_pv,
new_info->primitive_restart ? PR_ENABLE : PR_DISABLE,
&mode, &index_size, &new_draw->count,
&trans_func);
assert(new_info->mode == mode);
assert(new_info->index_size == index_size);
}
else {
enum pipe_prim_type mode = 0;
unsigned index_size;
u_index_generator(pc->cfg.primtypes_mask,
info->mode, draw->start, draw->count,
pc->api_pv, pc->api_pv,
&mode, &index_size, &new_draw->count,
&gen_func);
new_info->mode = mode;
new_info->index_size = index_size;
}
/* (step 5: allocate gpu memory sized for the FINAL index count) */
u_upload_alloc(pc->pipe->stream_uploader, 0, new_info->index_size * new_draw->count, 4,
&ib_offset, &new_info->index.resource, &dst);
new_draw->start = ib_offset / new_info->index_size;
new_draw->index_bias = info->index_size ? draw->index_bias : 0;
if (info->index_size) {
if (num_direct_draws) {
uint8_t *ptr = rewrite_buffer;
uint8_t *dst_ptr = dst;
/* step 6: if rewriting a prim-restart draw to direct draws,
* loop over all the direct draws in order to rewrite them into a single index buffer
* and draw in order to match the original call
*/
for (unsigned i = 0; i < num_direct_draws; i++) {
/* step 6a: get the index count for this draw, once converted */
unsigned tmp_count = u_index_count_converted_indices(pc->cfg.primtypes_mask, true, info->mode, direct_draws[i].count);
/* step 6b: handle index size conversion using the temp buffer; no change in index count
* TODO: this step can be optimized out if the index size is known to not change
*/
direct_draw_func(src, direct_draws[i].start, direct_draws[i].count, direct_draws[i].count, info->restart_index, ptr);
/* step 6c: handle the primitive type conversion rewriting to the converted index count */
trans_func(ptr, 0, direct_draws[i].count, tmp_count, info->restart_index, dst_ptr);
/* step 6d: increment the temp buffer and mapped final index buffer pointers */
ptr += new_info->index_size * direct_draws[i].count;
dst_ptr += new_info->index_size * tmp_count;
}
/* step 7: set the final index count, which is the converted total index count from the original draw rewrite */
new_draw->count = u_index_count_converted_indices(pc->cfg.primtypes_mask, true, info->mode, total_index_count);
} else
trans_func(src, draw->start, draw->count, new_draw->count, info->restart_index, dst);
if (pc->cfg.fixed_prim_restart && new_info->primitive_restart) {
new_info->restart_index = (1ull << (new_info->index_size * 8)) - 1;
if (info->restart_index != new_info->restart_index)
util_translate_prim_restart_data(new_info->index_size, dst, dst,
new_draw->count,
info->restart_index);
}
}
else {
gen_func(draw->start, new_draw->count, dst);
}
if (src_transfer)
pipe_buffer_unmap(pc->pipe, src_transfer);
u_upload_unmap(pc->pipe->stream_uploader);
free(direct_draws);
free(rewrite_buffer);
return true;
}
void
util_primconvert_draw_vbo(struct primconvert_context *pc,
const struct pipe_draw_info *info,
unsigned drawid_offset,
const struct pipe_draw_indirect_info *indirect,
const struct pipe_draw_start_count_bias *draws,
unsigned num_draws)
{
struct pipe_draw_info new_info;
struct pipe_draw_start_count_bias new_draw;
if (indirect && indirect->buffer) {
/* this is stupid, but we're already doing a readback,
* so this thing may as well get the rest of the job done
*/
unsigned draw_count = 0;
struct u_indirect_params *new_draws = util_draw_indirect_read(pc->pipe, info, indirect, &draw_count);
if (!new_draws)
return;
for (unsigned i = 0; i < draw_count; i++)
util_primconvert_draw_vbo(pc, &new_draws[i].info, drawid_offset + i, NULL, &new_draws[i].draw, 1);
free(new_draws);
return;
}
if (num_draws > 1) {
unsigned drawid = drawid_offset;
for (unsigned i = 0; i < num_draws; i++) {
if (draws[i].count && info->instance_count)
util_primconvert_draw_vbo(pc, info, drawid, NULL, &draws[i], 1);
if (info->increment_draw_id)
drawid++;
}
return;
}
if (!primconvert_init_draw(pc, info, indirect, draws, &new_info, &new_draw))
return;
/* to the translated draw: */
pc->pipe->draw_vbo(pc->pipe, &new_info, drawid_offset, NULL, &new_draw, 1);
pipe_resource_reference(&new_info.index.resource, NULL);
}
void
util_primconvert_draw_vertex_state(struct primconvert_context *pc,
struct pipe_vertex_state *vstate,
uint32_t partial_velem_mask,
struct pipe_draw_vertex_state_info info,
const struct pipe_draw_start_count_bias *draws,
unsigned num_draws)
{
struct pipe_draw_info new_info;
struct pipe_draw_start_count_bias new_draw;
if (pc->cfg.primtypes_mask & BITFIELD_BIT(info.mode)) {
pc->pipe->draw_vertex_state(pc->pipe, vstate, partial_velem_mask, info, draws, num_draws);
return;
}
if (num_draws > 1) {
for (unsigned i = 0; i < num_draws; i++) {
if (draws[i].count)
util_primconvert_draw_vertex_state(pc, vstate, partial_velem_mask, info, &draws[i], 1);
}
return;
}
struct pipe_draw_info dinfo = {0};
dinfo.mode = info.mode;
dinfo.index_size = 4;
dinfo.instance_count = 1;
dinfo.index.resource = vstate->input.indexbuf;
if (!primconvert_init_draw(pc, &dinfo, NULL, draws, &new_info, &new_draw))
return;
struct pipe_vertex_state *new_state = pc->pipe->screen->create_vertex_state(pc->pipe->screen,
&vstate->input.vbuffer,
vstate->input.elements,
vstate->input.num_elements,
new_info.index.resource,
vstate->input.full_velem_mask);
if (new_state) {
struct pipe_draw_vertex_state_info new_vinfo;
new_vinfo.mode = new_info.mode;
new_vinfo.take_vertex_state_ownership = true;
/* to the translated draw: */
pc->pipe->draw_vertex_state(pc->pipe, new_state, partial_velem_mask, new_vinfo, &new_draw, 1);
}
if (info.take_vertex_state_ownership)
pipe_vertex_state_reference(&vstate, NULL);
pipe_resource_reference(&new_info.index.resource, NULL);
}
+73
View File
@@ -0,0 +1,73 @@
/*
* Copyright (C) 2013 Rob Clark <robclark@freedesktop.org>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Authors:
* Rob Clark <robclark@freedesktop.org>
*/
#ifndef U_PRIMCONVERT_H_
#define U_PRIMCONVERT_H_
#include "pipe/p_state.h"
#ifdef __cplusplus
extern "C" {
#endif
struct primconvert_context;
struct primconvert_config {
uint32_t primtypes_mask;
uint32_t restart_primtypes_mask;
bool fixed_prim_restart;
};
struct primconvert_context *util_primconvert_create(struct pipe_context *pipe,
uint32_t primtypes_mask);
struct primconvert_context *util_primconvert_create_config(struct pipe_context *pipe,
struct primconvert_config *cfg);
void util_primconvert_destroy(struct primconvert_context *pc);
void util_primconvert_save_rasterizer_state(struct primconvert_context *pc,
const struct pipe_rasterizer_state
*rast);
void
util_primconvert_save_flatshade_first(struct primconvert_context *pc, bool flatshade_first);
void util_primconvert_draw_vbo(struct primconvert_context *pc,
const struct pipe_draw_info *info,
unsigned drawid_offset,
const struct pipe_draw_indirect_info *indirect,
const struct pipe_draw_start_count_bias *draws,
unsigned num_draws);
void
util_primconvert_draw_vertex_state(struct primconvert_context *pc,
struct pipe_vertex_state *state,
uint32_t partial_velem_mask,
struct pipe_draw_vertex_state_info info,
const struct pipe_draw_start_count_bias *draws,
unsigned num_draws);
#ifdef __cplusplus
}
#endif
#endif /* U_PRIMCONVERT_H_ */
+272
View File
@@ -0,0 +1,272 @@
copyright = '''
/*
* Copyright 2009 VMware, Inc.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* on the rights to use, copy, modify, merge, publish, distribute, sub
* license, and/or sell copies of the Software, and to permit persons to whom
* the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* VMWARE AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
'''
GENERATE, UBYTE, USHORT, UINT = 'generate', 'ubyte', 'ushort', 'uint'
FIRST, LAST = 'first', 'last'
INTYPES = (GENERATE, UBYTE, USHORT, UINT)
OUTTYPES = (USHORT, UINT)
PRIMS=('tris',
'trifan',
'tristrip',
'quads',
'quadstrip',
'polygon',
'trisadj',
'tristripadj')
LONGPRIMS=('PIPE_PRIM_TRIANGLES',
'PIPE_PRIM_TRIANGLE_FAN',
'PIPE_PRIM_TRIANGLE_STRIP',
'PIPE_PRIM_QUADS',
'PIPE_PRIM_QUAD_STRIP',
'PIPE_PRIM_POLYGON',
'PIPE_PRIM_TRIANGLES_ADJACENCY',
'PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY')
longprim = dict(zip(PRIMS, LONGPRIMS))
intype_idx = dict(ubyte='IN_UBYTE', ushort='IN_USHORT', uint='IN_UINT')
outtype_idx = dict(ushort='OUT_USHORT', uint='OUT_UINT')
def prolog():
print('''/* File automatically generated by u_unfilled_gen.py */''')
print(copyright)
print(r'''
/**
* @file
* Functions to translate and generate index lists
*/
#include "indices/u_indices.h"
#include "indices/u_indices_priv.h"
#include "pipe/p_compiler.h"
#include "util/u_debug.h"
#include "pipe/p_defines.h"
#include "util/u_memory.h"
static unsigned out_size_idx( unsigned index_size )
{
switch (index_size) {
case 4: return OUT_UINT;
case 2: return OUT_USHORT;
default: assert(0); return OUT_USHORT;
}
}
static unsigned in_size_idx( unsigned index_size )
{
switch (index_size) {
case 4: return IN_UINT;
case 2: return IN_USHORT;
case 1: return IN_UBYTE;
default: assert(0); return IN_UBYTE;
}
}
static u_generate_func generate_line[OUT_COUNT][PRIM_COUNT];
static u_translate_func translate_line[IN_COUNT][OUT_COUNT][PRIM_COUNT];
''')
def vert( intype, outtype, v0 ):
if intype == GENERATE:
return '(' + outtype + ')(' + v0 + ')'
else:
return '(' + outtype + ')in[' + v0 + ']'
def line( intype, outtype, ptr, v0, v1 ):
print(' (' + ptr + ')[0] = ' + vert( intype, outtype, v0 ) + ';')
print(' (' + ptr + ')[1] = ' + vert( intype, outtype, v1 ) + ';')
# XXX: have the opportunity here to avoid over-drawing shared lines in
# tristrips, fans, etc, by integrating this into the calling functions
# and only emitting each line at most once.
#
def do_tri( intype, outtype, ptr, v0, v1, v2 ):
line( intype, outtype, ptr, v0, v1 )
line( intype, outtype, ptr + '+2', v1, v2 )
line( intype, outtype, ptr + '+4', v2, v0 )
def do_quad( intype, outtype, ptr, v0, v1, v2, v3 ):
line( intype, outtype, ptr, v0, v1 )
line( intype, outtype, ptr + '+2', v1, v2 )
line( intype, outtype, ptr + '+4', v2, v3 )
line( intype, outtype, ptr + '+6', v3, v0 )
def name(intype, outtype, prim):
if intype == GENERATE:
return 'generate_' + prim + '_' + outtype
else:
return 'translate_' + prim + '_' + intype + '2' + outtype
def preamble(intype, outtype, prim):
print('static void ' + name( intype, outtype, prim ) + '(')
if intype != GENERATE:
print(' const void * _in,')
print(' unsigned start,')
if intype != GENERATE:
print(' unsigned in_nr,')
print(' unsigned out_nr,')
if intype != GENERATE:
print(' unsigned restart_index,')
print(' void *_out )')
print('{')
if intype != GENERATE:
print(' const ' + intype + '*in = (const ' + intype + '*)_in;')
print(' ' + outtype + ' *out = (' + outtype + '*)_out;')
print(' unsigned i, j;')
print(' (void)j;')
def postamble():
print('}')
def tris(intype, outtype):
preamble(intype, outtype, prim='tris')
print(' for (i = start, j = 0; j < out_nr; j+=6, i+=3) { ')
do_tri( intype, outtype, 'out+j', 'i', 'i+1', 'i+2' );
print(' }')
postamble()
def tristrip(intype, outtype):
preamble(intype, outtype, prim='tristrip')
print(' for (i = start, j = 0; j < out_nr; j+=6, i++) { ')
do_tri( intype, outtype, 'out+j', 'i', 'i+1/*+(i&1)*/', 'i+2/*-(i&1)*/' );
print(' }')
postamble()
def trifan(intype, outtype):
preamble(intype, outtype, prim='trifan')
print(' for (i = start, j = 0; j < out_nr; j+=6, i++) { ')
do_tri( intype, outtype, 'out+j', '0', 'i+1', 'i+2' );
print(' }')
postamble()
def polygon(intype, outtype):
preamble(intype, outtype, prim='polygon')
print(' for (i = start, j = 0; j < out_nr; j+=2, i++) { ')
line( intype, outtype, 'out+j', 'i', '(i+1)%(out_nr/2)' )
print(' }')
postamble()
def quads(intype, outtype):
preamble(intype, outtype, prim='quads')
print(' for (i = start, j = 0; j < out_nr; j+=8, i+=4) { ')
do_quad( intype, outtype, 'out+j', 'i+0', 'i+1', 'i+2', 'i+3' );
print(' }')
postamble()
def quadstrip(intype, outtype):
preamble(intype, outtype, prim='quadstrip')
print(' for (i = start, j = 0; j < out_nr; j+=8, i+=2) { ')
do_quad( intype, outtype, 'out+j', 'i+2', 'i+0', 'i+1', 'i+3' );
print(' }')
postamble()
def trisadj(intype, outtype):
preamble(intype, outtype, prim='trisadj')
print(' for (i = start, j = 0; j < out_nr; j+=6, i+=6) { ')
do_tri( intype, outtype, 'out+j', 'i', 'i+2', 'i+4' );
print(' }')
postamble()
def tristripadj(intype, outtype):
preamble(intype, outtype, prim='tristripadj')
print(' for (i = start, j = 0; j < out_nr; j+=6, i+=2) { ')
do_tri( intype, outtype, 'out+j', 'i', 'i+2', 'i+4' );
print(' }')
postamble()
def emit_funcs():
for intype in INTYPES:
for outtype in OUTTYPES:
tris(intype, outtype)
tristrip(intype, outtype)
trifan(intype, outtype)
quads(intype, outtype)
quadstrip(intype, outtype)
polygon(intype, outtype)
trisadj(intype, outtype)
tristripadj(intype, outtype)
def init(intype, outtype, prim):
if intype == GENERATE:
print(('generate_line[' +
outtype_idx[outtype] +
'][' + longprim[prim] +
'] = ' + name( intype, outtype, prim ) + ';'))
else:
print(('translate_line[' +
intype_idx[intype] +
'][' + outtype_idx[outtype] +
'][' + longprim[prim] +
'] = ' + name( intype, outtype, prim ) + ';'))
def emit_all_inits():
for intype in INTYPES:
for outtype in OUTTYPES:
for prim in PRIMS:
init(intype, outtype, prim)
def emit_init():
print('void u_unfilled_init( void )')
print('{')
print(' static int firsttime = 1;')
print(' if (!firsttime) return;')
print(' firsttime = 0;')
emit_all_inits()
print('}')
def epilog():
print('#include "indices/u_unfilled_indices.c"')
def main():
prolog()
emit_funcs()
emit_init()
epilog()
if __name__ == '__main__':
main()
+225
View File
@@ -0,0 +1,225 @@
/*
* Copyright 2009 VMware, Inc.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* on the rights to use, copy, modify, merge, publish, distribute, sub
* license, and/or sell copies of the Software, and to permit persons to whom
* the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* VMWARE AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/*
* NOTE: This file is not compiled by itself. It's actually #included
* by the generated u_unfilled_gen.c file!
*/
#include "u_indices.h"
#include "u_indices_priv.h"
#include "util/u_prim.h"
static void translate_ubyte_ushort( const void *in,
unsigned start,
unsigned in_nr,
unsigned out_nr,
unsigned restart_index,
void *out )
{
const ubyte *in_ub = (const ubyte *)in;
ushort *out_us = (ushort *)out;
unsigned i;
for (i = 0; i < out_nr; i++)
out_us[i] = (ushort) in_ub[i+start];
}
static void translate_memcpy_ushort( const void *in,
unsigned start,
unsigned in_nr,
unsigned out_nr,
unsigned restart_index,
void *out )
{
memcpy(out, &((short *)in)[start], out_nr*sizeof(short));
}
static void translate_memcpy_uint( const void *in,
unsigned start,
unsigned in_nr,
unsigned out_nr,
unsigned restart_index,
void *out )
{
memcpy(out, &((int *)in)[start], out_nr*sizeof(int));
}
static void generate_linear_ushort( unsigned start,
unsigned nr,
void *out )
{
ushort *out_us = (ushort *)out;
unsigned i;
for (i = 0; i < nr; i++)
out_us[i] = (ushort)(i + start);
}
static void generate_linear_uint( unsigned start,
unsigned nr,
void *out )
{
unsigned *out_ui = (unsigned *)out;
unsigned i;
for (i = 0; i < nr; i++)
out_ui[i] = i + start;
}
/**
* Given a primitive type and number of vertices, return the number of vertices
* needed to draw the primitive with fill mode = PIPE_POLYGON_MODE_LINE using
* separate lines (PIPE_PRIM_LINES).
*/
static unsigned
nr_lines(enum pipe_prim_type prim, unsigned nr)
{
switch (prim) {
case PIPE_PRIM_TRIANGLES:
return (nr / 3) * 6;
case PIPE_PRIM_TRIANGLE_STRIP:
return (nr - 2) * 6;
case PIPE_PRIM_TRIANGLE_FAN:
return (nr - 2) * 6;
case PIPE_PRIM_QUADS:
return (nr / 4) * 8;
case PIPE_PRIM_QUAD_STRIP:
return (nr - 2) / 2 * 8;
case PIPE_PRIM_POLYGON:
return 2 * nr; /* a line (two verts) for each polygon edge */
/* Note: these cases can't really be handled since drawing lines instead
* of triangles would also require changing the GS. But if there's no GS,
* this should work.
*/
case PIPE_PRIM_TRIANGLES_ADJACENCY:
return (nr / 6) * 6;
case PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY:
return ((nr - 4) / 2) * 6;
default:
assert(0);
return 0;
}
}
enum indices_mode
u_unfilled_translator(enum pipe_prim_type prim,
unsigned in_index_size,
unsigned nr,
unsigned unfilled_mode,
enum pipe_prim_type *out_prim,
unsigned *out_index_size,
unsigned *out_nr,
u_translate_func *out_translate)
{
unsigned in_idx;
unsigned out_idx;
assert(u_reduced_prim(prim) == PIPE_PRIM_TRIANGLES);
u_unfilled_init();
in_idx = in_size_idx(in_index_size);
*out_index_size = (in_index_size == 4) ? 4 : 2;
out_idx = out_size_idx(*out_index_size);
if (unfilled_mode == PIPE_POLYGON_MODE_POINT) {
*out_prim = PIPE_PRIM_POINTS;
*out_nr = nr;
switch (in_index_size) {
case 1:
*out_translate = translate_ubyte_ushort;
return U_TRANSLATE_NORMAL;
case 2:
*out_translate = translate_memcpy_uint;
return U_TRANSLATE_MEMCPY;
case 4:
*out_translate = translate_memcpy_ushort;
return U_TRANSLATE_MEMCPY;
default:
*out_translate = translate_memcpy_uint;
*out_nr = 0;
assert(0);
return U_TRANSLATE_ERROR;
}
}
else {
assert(unfilled_mode == PIPE_POLYGON_MODE_LINE);
*out_prim = PIPE_PRIM_LINES;
*out_translate = translate_line[in_idx][out_idx][prim];
*out_nr = nr_lines( prim, nr );
return U_TRANSLATE_NORMAL;
}
}
/**
* Utility for converting unfilled polygons into points, lines, triangles.
* Few drivers have direct support for OpenGL's glPolygonMode.
* This function helps with converting triangles into points or lines
* when the front and back fill modes are the same. When there's
* different front/back fill modes, that can be handled with the
* 'draw' module.
*/
enum indices_mode
u_unfilled_generator(enum pipe_prim_type prim,
unsigned start,
unsigned nr,
unsigned unfilled_mode,
enum pipe_prim_type *out_prim,
unsigned *out_index_size,
unsigned *out_nr,
u_generate_func *out_generate)
{
unsigned out_idx;
assert(u_reduced_prim(prim) == PIPE_PRIM_TRIANGLES);
u_unfilled_init();
*out_index_size = ((start + nr) > 0xfffe) ? 4 : 2;
out_idx = out_size_idx(*out_index_size);
if (unfilled_mode == PIPE_POLYGON_MODE_POINT) {
if (*out_index_size == 4)
*out_generate = generate_linear_uint;
else
*out_generate = generate_linear_ushort;
*out_prim = PIPE_PRIM_POINTS;
*out_nr = nr;
return U_GENERATE_LINEAR;
}
else {
assert(unfilled_mode == PIPE_POLYGON_MODE_LINE);
*out_prim = PIPE_PRIM_LINES;
*out_generate = generate_line[out_idx][prim];
*out_nr = nr_lines( prim, nr );
return U_GENERATE_REUSABLE;
}
}
+21 -1
View File
@@ -150,6 +150,10 @@ files_mesa_util = files(
'vma.c',
'vma.h',
'xxhash.h',
'indices/u_indices.h',
'indices/u_indices_priv.h',
'indices/u_primconvert.c',
'indices/u_primconvert.h',
)
files_drirc = files('00-mesa-defaults.conf')
@@ -227,9 +231,25 @@ endif
u_trace_py = files('perf/u_trace.py')
u_indices_gen_c = custom_target(
'u_indices_gen.c',
input : 'indices/u_indices_gen.py',
output : 'u_indices_gen.c',
command : [prog_python, '@INPUT@'],
capture : true,
)
u_unfilled_gen_c = custom_target(
'u_unfilled_gen.c',
input : 'indices/u_unfilled_gen.py',
output : 'u_unfilled_gen.c',
command : [prog_python, '@INPUT@'],
capture : true,
)
_libmesa_util = static_library(
'mesa_util',
[files_mesa_util, files_debug_stack, format_srgb],
[files_mesa_util, files_debug_stack, format_srgb, u_indices_gen_c, u_unfilled_gen_c],
include_directories : [inc_include, inc_src, inc_mapi, inc_mesa, inc_gallium, inc_gallium_aux],
dependencies : deps_for_libmesa_util,
link_with: libmesa_format,