This commit is contained in:
elwrcl committed 2026-06-06 13:25:15 +03:00
1 parent 04d4dc8b09
commit 818cab85dc
12511 files changed
+6156641

No files matched your search

+107
View File
@@ -0,0 +1,107 @@
CROSS-PLATFORM PORTABILITY GUIDELINES FOR GALLIUM3D
= General Considerations =
The frontend and winsys driver support a rather limited number of
platforms. However, the pipe drivers are meant to run in a wide number of
platforms. Hence the pipe drivers, the auxiliary modules, and all public
headers in general, should strictly follow these guidelines to ensure
= Compiler Support =
* Include the util/compiler.h.
* Cast explicitly when converting to integer types of smaller sizes.
* Cast explicitly when converting between float, double and integral types.
* Don't use named struct initializers.
* Don't use variable number of macro arguments. Use static inline functions
instead.
* Don't use C99 features.
= Standard Library =
* Avoid including standard library headers. Most standard library functions are
not available in Windows Kernel Mode. Use the appropriate p_*.h include.
== Memory Allocation ==
* Use MALLOC, CALLOC, FREE instead of the malloc, calloc, free functions.
* Use align_pointer() function defined in u_memory.h for aligning pointers
in a portable way.
== Debugging ==
* Use the functions/macros in p_debug.h.
* Don't include assert.h, call abort, printf, etc.
= Code Style =
== Inherantice in C ==
The main thing we do is mimic inheritance by structure containment.
Here's a silly made-up example:
/* base class */
struct buffer
{
int size;
void (*validate)(struct buffer *buf);
};
/* sub-class of bufffer */
struct texture_buffer
{
struct buffer base; /* the base class, MUST COME FIRST! */
int format;
int width, height;
};
Then, we'll typically have cast-wrapper functions to convert base-class
pointers to sub-class pointers where needed:
static inline struct vertex_buffer *vertex_buffer(struct buffer *buf)
{
return (struct vertex_buffer *) buf;
}
To create/init a sub-classed object:
struct buffer *create_texture_buffer(int w, int h, int format)
{
struct texture_buffer *t = malloc(sizeof(*t));
t->format = format;
t->width = w;
t->height = h;
t->base.size = w * h;
t->base.validate = tex_validate;
return &t->base;
}
Example sub-class method:
void tex_validate(struct buffer *buf)
{
struct texture_buffer *tb = texture_buffer(buf);
assert(tb->format);
assert(tb->width);
assert(tb->height);
}
Note that we typically do not use typedefs to make "class names"; we use
'struct whatever' everywhere.
Gallium's pipe_context and the subclassed psb_context, etc are prime examples
of this. There's also many examples in Mesa and the Mesa state tracker.
+207
View File
@@ -0,0 +1,207 @@
/**************************************************************************
*
* Copyright 2007 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 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 ITS 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.
*
**************************************************************************/
/* Authors: Zack Rusin <[email protected]>
*/
#include "util/u_debug.h"
#include "util/u_memory.h"
#include "cso_cache.h"
#include "cso_hash.h"
/* Default delete callback. It can also be used by custom callbacks. */
void
cso_delete_state(struct pipe_context *pipe, void *state,
enum cso_cache_type type)
{
switch (type) {
case CSO_BLEND:
pipe->delete_blend_state(pipe, ((struct cso_blend*)state)->data);
break;
case CSO_SAMPLER:
pipe->delete_sampler_state(pipe, ((struct cso_sampler*)state)->data);
break;
case CSO_DEPTH_STENCIL_ALPHA:
pipe->delete_depth_stencil_alpha_state(pipe,
((struct cso_depth_stencil_alpha*)state)->data);
break;
case CSO_RASTERIZER:
pipe->delete_rasterizer_state(pipe, ((struct cso_rasterizer*)state)->data);
break;
case CSO_VELEMENTS:
pipe->delete_vertex_elements_state(pipe, ((struct cso_velements*)state)->data);
break;
default:
assert(0);
}
FREE(state);
}
static inline void
sanitize_hash(struct cso_cache *sc,
struct cso_hash *hash,
enum cso_cache_type type,
int max_size)
{
if (sc->sanitize_cb)
sc->sanitize_cb(hash, type, max_size, sc->sanitize_data);
}
static inline void
sanitize_cb(struct cso_hash *hash, enum cso_cache_type type,
int max_size, void *user_data)
{
struct cso_cache *cache = (struct cso_cache *)user_data;
/* if we're approach the maximum size, remove fourth of the entries
* otherwise every subsequent call will go through the same */
int hash_size = cso_hash_size(hash);
int max_entries = (max_size > hash_size) ? max_size : hash_size;
int to_remove = (max_size < max_entries) * max_entries/4;
if (hash_size > max_size)
to_remove += hash_size - max_size;
while (to_remove) {
/*remove elements until we're good */
/*fixme: currently we pick the nodes to remove at random*/
struct cso_hash_iter iter = cso_hash_first_node(hash);
void *cso = cso_hash_take(hash, cso_hash_iter_key(iter));
cache->delete_cso(cache->delete_cso_ctx, cso, type);
--to_remove;
}
}
struct cso_hash_iter
cso_insert_state(struct cso_cache *sc,
unsigned hash_key, enum cso_cache_type type,
void *state)
{
struct cso_hash *hash = &sc->hashes[type];
sanitize_hash(sc, hash, type, sc->max_size);
return cso_hash_insert(hash, hash_key, state);
}
void *
cso_hash_find_data_from_template(struct cso_hash *hash,
unsigned hash_key,
void *templ,
int size )
{
struct cso_hash_iter iter = cso_hash_find(hash, hash_key);
while (!cso_hash_iter_is_null(iter)) {
void *iter_data = cso_hash_iter_data(iter);
if (!memcmp(iter_data, templ, size)) {
/* We found a match */
return iter_data;
}
iter = cso_hash_iter_next(iter);
}
return NULL;
}
void
cso_cache_init(struct cso_cache *sc, struct pipe_context *pipe)
{
memset(sc, 0, sizeof(*sc));
sc->max_size = 4096;
for (int i = 0; i < CSO_CACHE_MAX; i++)
cso_hash_init(&sc->hashes[i]);
sc->sanitize_cb = sanitize_cb;
sc->sanitize_data = sc;
sc->delete_cso = (cso_delete_cso_callback)cso_delete_state;
sc->delete_cso_ctx = pipe;
}
static void
cso_delete_all(struct cso_cache *sc, enum cso_cache_type type)
{
struct cso_hash *hash = &sc->hashes[type];
struct cso_hash_iter iter = cso_hash_first_node(hash);
while (!cso_hash_iter_is_null(iter)) {
void *state = cso_hash_iter_data(iter);
iter = cso_hash_iter_next(iter);
if (state) {
sc->delete_cso(sc->delete_cso_ctx, state, type);
}
}
}
void
cso_cache_delete(struct cso_cache *sc)
{
/* delete driver data */
cso_delete_all(sc, CSO_BLEND);
cso_delete_all(sc, CSO_DEPTH_STENCIL_ALPHA);
cso_delete_all(sc, CSO_RASTERIZER);
cso_delete_all(sc, CSO_SAMPLER);
cso_delete_all(sc, CSO_VELEMENTS);
for (int i = 0; i < CSO_CACHE_MAX; i++)
cso_hash_deinit(&sc->hashes[i]);
}
void
cso_set_maximum_cache_size(struct cso_cache *sc, int number)
{
sc->max_size = number;
for (int i = 0; i < CSO_CACHE_MAX; i++)
sanitize_hash(sc, &sc->hashes[i], i, sc->max_size);
}
void
cso_cache_set_sanitize_callback(struct cso_cache *sc,
cso_sanitize_callback cb,
void *user_data)
{
sc->sanitize_cb = cb;
sc->sanitize_data = user_data;
}
void
cso_cache_set_delete_cso_callback(struct cso_cache *sc,
cso_delete_cso_callback delete_cso,
void *ctx)
{
sc->delete_cso = delete_cso;
sc->delete_cso_ctx = ctx;
}
+214
View File
@@ -0,0 +1,214 @@
/**************************************************************************
*
* Copyright 2007-2008 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 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 ITS 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.
*
**************************************************************************/
/**
* @file
* Constant State Object (CSO) cache.
*
* The basic idea is that the states are created via the
* create_state/bind_state/delete_state semantics. The driver is expected to
* perform as much of the Gallium state translation to whatever its internal
* representation is during the create call. Gallium then has a caching
* mechanism where it stores the created states. When the pipeline needs an
* actual state change, a bind call is issued. In the bind call the driver
* gets its already translated representation.
*
* Those semantics mean that the driver doesn't do the repeated translations
* of states on every frame, but only once, when a new state is actually
* created.
*
* Even on hardware that doesn't do any kind of state cache, it makes the
* driver look a lot neater, plus it avoids all the redundant state
* translations on every frame.
*
* Currently our constant state objects are:
* - alpha test
* - blend
* - depth stencil
* - fragment shader
* - rasterizer (old setup)
* - sampler
* - vertex shader
* - vertex elements
*
* Things that are not constant state objects include:
* - blend_color
* - clip_state
* - clear_color_state
* - constant_buffer
* - feedback_state
* - framebuffer_state
* - polygon_stipple
* - scissor_state
* - texture_state
* - viewport_state
*
* @author Zack Rusin <[email protected]>
*/
#ifndef CSO_CACHE_H
#define CSO_CACHE_H
#include "pipe/p_context.h"
#include "pipe/p_state.h"
/* cso_hash.h is necessary for cso_hash_iter, as MSVC requires structures
* returned by value to be fully defined */
#include "cso_hash.h"
#ifdef __cplusplus
extern "C" {
#endif
enum cso_cache_type {
CSO_RASTERIZER,
CSO_BLEND,
CSO_DEPTH_STENCIL_ALPHA,
CSO_SAMPLER,
CSO_VELEMENTS,
CSO_CACHE_MAX,
};
typedef void (*cso_delete_cso_callback)(void *ctx, void *state,
enum cso_cache_type type);
typedef void (*cso_state_callback)(void *ctx, void *obj);
typedef void (*cso_sanitize_callback)(struct cso_hash *hash,
enum cso_cache_type type,
int max_size,
void *user_data);
struct cso_cache {
struct cso_hash hashes[CSO_CACHE_MAX];
int max_size;
cso_sanitize_callback sanitize_cb;
void *sanitize_data;
cso_delete_cso_callback delete_cso;
void *delete_cso_ctx;
};
struct cso_blend {
struct pipe_blend_state state;
void *data;
};
struct cso_depth_stencil_alpha {
struct pipe_depth_stencil_alpha_state state;
void *data;
};
struct cso_rasterizer {
struct pipe_rasterizer_state state;
void *data;
};
struct cso_sampler {
struct pipe_sampler_state state;
void *data;
unsigned hash_key;
};
struct cso_velems_state {
unsigned count;
struct pipe_vertex_element velems[PIPE_MAX_ATTRIBS];
};
struct cso_velements {
struct cso_velems_state state;
void *data;
};
void
cso_cache_init(struct cso_cache *sc, struct pipe_context *pipe);
void
cso_cache_delete(struct cso_cache *sc);
void
cso_cache_set_sanitize_callback(struct cso_cache *sc,
cso_sanitize_callback cb,
void *user_data);
void
cso_cache_set_delete_cso_callback(struct cso_cache *sc,
cso_delete_cso_callback delete_cso,
void *ctx);
struct cso_hash_iter
cso_insert_state(struct cso_cache *sc,
unsigned hash_key, enum cso_cache_type type,
void *state);
void
cso_set_maximum_cache_size(struct cso_cache *sc, int number);
void
cso_delete_state(struct pipe_context *pipe, void *state,
enum cso_cache_type type);
static ALWAYS_INLINE unsigned
cso_construct_key(const void *key, int key_size)
{
unsigned hash = 0;
const unsigned *ikey = (const unsigned *)key;
unsigned num_elements = key_size / 4;
assert(key_size % 4 == 0);
for (unsigned i = 0; i < num_elements; i++)
hash ^= ikey[i];
return hash;
}
static ALWAYS_INLINE struct cso_hash_iter
cso_find_state_template(struct cso_cache *sc, unsigned hash_key,
enum cso_cache_type type, const void *key,
unsigned key_size)
{
struct cso_hash *hash = &sc->hashes[type];
struct cso_hash_iter iter = cso_hash_find(hash, hash_key);
while (!cso_hash_iter_is_null(iter)) {
void *iter_data = cso_hash_iter_data(iter);
if (!memcmp(iter_data, key, key_size))
return iter;
iter = cso_hash_iter_next(iter);
}
return iter;
}
#ifdef __cplusplus
}
#endif
#endif
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,260 @@
/**************************************************************************
*
* Copyright 2007-2008 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 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 ITS 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 CSO_CONTEXT_H
#define CSO_CONTEXT_H
#include "pipe/p_context.h"
#include "pipe/p_state.h"
#include "pipe/p_defines.h"
#include "cso_cache.h"
#ifdef __cplusplus
extern "C" {
#endif
struct cso_context {
struct pipe_context *pipe;
/* This is equal to either pipe_context::draw_vbo or u_vbuf_draw_vbo. */
pipe_draw_func draw_vbo;
};
#define CSO_NO_USER_VERTEX_BUFFERS (1 << 0)
#define CSO_NO_64B_VERTEX_BUFFERS (1 << 1)
#define CSO_NO_VBUF (1 << 2)
struct cso_context *
cso_create_context(struct pipe_context *pipe, unsigned flags);
void
cso_unbind_context(struct cso_context *ctx);
void
cso_destroy_context(struct cso_context *cso);
enum pipe_error
cso_set_blend(struct cso_context *cso, const struct pipe_blend_state *blend);
enum pipe_error
cso_set_depth_stencil_alpha(struct cso_context *cso,
const struct pipe_depth_stencil_alpha_state *dsa);
enum pipe_error
cso_set_rasterizer(struct cso_context *cso,
const struct pipe_rasterizer_state *rasterizer);
void
cso_set_samplers(struct cso_context *cso,
mesa_shader_stage shader_stage,
unsigned count,
const struct pipe_sampler_state **states);
/* Alternate interface to support gallium frontends that like to modify
* samplers one at a time:
*/
void
cso_single_sampler(struct cso_context *cso, mesa_shader_stage shader_stage,
unsigned idx, const struct pipe_sampler_state *states);
void
cso_single_sampler_done(struct cso_context *cso,
mesa_shader_stage shader_stage);
void *
cso_get_vertex_elements_for_bind(struct cso_context *cso,
const struct cso_velems_state *velems);
enum pipe_error
cso_set_vertex_elements(struct cso_context *ctx,
const struct cso_velems_state *velems);
void cso_set_vertex_buffers(struct cso_context *ctx,
unsigned count,
const struct pipe_vertex_buffer *buffers);
void cso_set_stream_outputs(struct cso_context *ctx,
unsigned num_targets,
struct pipe_stream_output_target **targets,
const unsigned *offsets,
enum mesa_prim output_prim);
enum cso_unbind_flags {
CSO_UNBIND_FS_SAMPLERVIEWS = (1 << 0),
CSO_UNBIND_FS_SAMPLERVIEW0 = (1 << 1),
CSO_UNBIND_FS_IMAGE0 = (1 << 2),
CSO_UNBIND_VS_CONSTANTS = (1 << 3),
CSO_UNBIND_FS_CONSTANTS = (1 << 4),
};
/*
* We don't provide shader caching in CSO. Most of the time the api provides
* object semantics for shaders anyway, and the cases where it doesn't
* (eg mesa's internally-generated texenv programs), it will be up to
* gallium frontends to implement their own specialized caching.
*/
void cso_set_fragment_shader_handle(struct cso_context *ctx, void *handle);
void cso_set_vertex_shader_handle(struct cso_context *ctx, void *handle);
void cso_set_geometry_shader_handle(struct cso_context *ctx, void *handle);
void cso_set_tessctrl_shader_handle(struct cso_context *ctx, void *handle);
void cso_set_tesseval_shader_handle(struct cso_context *ctx, void *handle);
void cso_set_compute_shader_handle(struct cso_context *ctx, void *handle);
void cso_set_task_shader_handle(struct cso_context *ctx, void *handle);
void cso_set_mesh_shader_handle(struct cso_context *ctx, void *handle);
void
cso_set_framebuffer(struct cso_context *cso,
const struct pipe_framebuffer_state *fb);
void
cso_set_viewport(struct cso_context *cso,
const struct pipe_viewport_state *vp);
void
cso_set_viewport_dims(struct cso_context *ctx,
float width, float height, bool invert);
void
cso_set_sample_mask(struct cso_context *cso, unsigned stencil_mask);
void
cso_set_min_samples(struct cso_context *cso, unsigned min_samples);
void
cso_set_stencil_ref(struct cso_context *cso,
const struct pipe_stencil_ref sr);
void
cso_set_render_condition(struct cso_context *cso,
struct pipe_query *query,
bool condition,
enum pipe_render_cond_flag mode);
/* gap */
#define CSO_BIT_BLEND 0x2
#define CSO_BIT_DEPTH_STENCIL_ALPHA 0x4
#define CSO_BIT_FRAGMENT_SAMPLERS 0x8
/* gap */
#define CSO_BIT_FRAGMENT_SHADER 0x20
#define CSO_BIT_FRAMEBUFFER 0x40
#define CSO_BIT_GEOMETRY_SHADER 0x80
#define CSO_BIT_MIN_SAMPLES 0x100
#define CSO_BIT_RASTERIZER 0x200
#define CSO_BIT_RENDER_CONDITION 0x400
#define CSO_BIT_SAMPLE_MASK 0x800
#define CSO_BIT_STENCIL_REF 0x1000
#define CSO_BIT_STREAM_OUTPUTS 0x2000
#define CSO_BIT_TESSCTRL_SHADER 0x4000
#define CSO_BIT_TESSEVAL_SHADER 0x8000
#define CSO_BIT_VERTEX_ELEMENTS 0x10000
#define CSO_BIT_VERTEX_SHADER 0x20000
#define CSO_BIT_VIEWPORT 0x40000
#define CSO_BIT_PAUSE_QUERIES 0x80000
#define CSO_BIT_TASK_SHADER 0x100000
#define CSO_BIT_MESH_SHADER 0x200000
#define CSO_BITS_VERTEX_PIPE_SHADERS \
(CSO_BIT_VERTEX_SHADER | \
CSO_BIT_FRAGMENT_SHADER | \
CSO_BIT_GEOMETRY_SHADER | \
CSO_BIT_TESSCTRL_SHADER | \
CSO_BIT_TESSEVAL_SHADER)
#define CSO_BITS_MESH_PIPE_SHADERS \
(CSO_BIT_TASK_SHADER | \
CSO_BIT_MESH_SHADER | \
CSO_BIT_FRAGMENT_SHADER)
#define CSO_BIT_COMPUTE_SHADER (1<<0)
#define CSO_BIT_COMPUTE_SAMPLERS (1<<1)
void
cso_save_state(struct cso_context *cso, unsigned state_mask);
void
cso_restore_state(struct cso_context *cso, unsigned unbind);
void
cso_save_compute_state(struct cso_context *cso, unsigned state_mask);
void
cso_restore_compute_state(struct cso_context *cso);
/* Optimized version. */
void
cso_set_vertex_buffers_and_elements(struct cso_context *ctx,
const struct cso_velems_state *velems,
unsigned vb_count,
bool uses_user_vertex_buffers,
const struct pipe_vertex_buffer *vbuffers);
void
cso_draw_arrays_instanced(struct cso_context *cso, unsigned mode,
unsigned start, unsigned count,
unsigned start_instance, unsigned instance_count);
void
cso_draw_arrays(struct cso_context *cso, unsigned mode, unsigned start, unsigned count);
/* Inline functions. */
static ALWAYS_INLINE void
cso_draw_vbo(struct cso_context *cso,
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)
{
/* We can't have both indirect drawing and SO-vertex-count drawing */
assert(!indirect ||
indirect->buffer == NULL ||
indirect->count_from_stream_output == NULL);
/* We can't have SO-vertex-count drawing with an index buffer */
assert(info->index_size == 0 ||
!indirect ||
indirect->count_from_stream_output == NULL);
/* Indirect only uses indirect->draw_count, not num_draws. */
assert(!indirect || num_draws == 1);
cso->draw_vbo(cso->pipe, info, drawid_offset, indirect, draws, num_draws);
}
#ifdef __cplusplus
}
#endif
#endif
+327
View File
@@ -0,0 +1,327 @@
/**************************************************************************
*
* Copyright 2007 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 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 ITS 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.
*
**************************************************************************/
/*
* Authors:
* Zack Rusin <[email protected]>
*/
#include "util/u_debug.h"
#include "util/u_memory.h"
#include "util/bitscan.h"
#include "cso_hash.h"
#ifndef MAX
#define MAX(a, b) ((a > b) ? (a) : (b))
#endif
static const int MinNumBits = 4;
static const unsigned char prime_deltas[] = {
0, 0, 1, 3, 1, 5, 3, 3, 1, 9, 7, 5, 3, 9, 25, 3,
1, 21, 3, 21, 7, 15, 9, 5, 3, 29, 15, 0, 0, 0, 0, 0
};
static int
primeForNumBits(int numBits)
{
return (1 << numBits) + prime_deltas[numBits];
}
/*
* Returns the smallest integer n such that
* primeForNumBits(n) >= hint.
*/
static int
countBits(int hint)
{
int numBits = util_bitcount(hint);
if (numBits >= (int)sizeof(prime_deltas)) {
numBits = sizeof(prime_deltas) - 1;
} else if (primeForNumBits(numBits) < hint) {
++numBits;
}
return numBits;
}
static struct cso_node *
cso_hash_create_node(struct cso_hash *hash,
unsigned akey, void *avalue,
struct cso_node **anextNode)
{
struct cso_node *node = MALLOC(sizeof(struct cso_node));
if (!node)
return NULL;
node->key = akey;
node->value = avalue;
node->next = *anextNode;
*anextNode = node;
++hash->size;
return node;
}
static void
cso_data_rehash(struct cso_hash *hash, int hint)
{
if (hint < 0) {
hint = countBits(-hint);
if (hint < MinNumBits)
hint = MinNumBits;
hash->userNumBits = (short)hint;
while (primeForNumBits(hint) < (hash->size >> 1))
++hint;
} else if (hint < MinNumBits) {
hint = MinNumBits;
}
if (hash->numBits != hint) {
struct cso_node *e = (struct cso_node *)hash;
struct cso_node **oldBuckets = hash->buckets;
const int oldNumBuckets = hash->numBuckets;
hash->numBits = (short)hint;
hash->numBuckets = primeForNumBits(hint);
hash->buckets = MALLOC(sizeof(struct cso_node*) * hash->numBuckets);
for (int i = 0; i < hash->numBuckets; ++i)
hash->buckets[i] = e;
for (int i = 0; i < oldNumBuckets; ++i) {
struct cso_node *firstNode = oldBuckets[i];
while (firstNode != e) {
unsigned h = firstNode->key;
struct cso_node *lastNode = firstNode;
struct cso_node *afterLastNode;
struct cso_node **beforeFirstNode;
while (lastNode->next != e && lastNode->next->key == h)
lastNode = lastNode->next;
afterLastNode = lastNode->next;
beforeFirstNode = &hash->buckets[h % hash->numBuckets];
while (*beforeFirstNode != e)
beforeFirstNode = &(*beforeFirstNode)->next;
lastNode->next = *beforeFirstNode;
*beforeFirstNode = firstNode;
firstNode = afterLastNode;
}
}
FREE(oldBuckets);
}
}
static void
cso_data_might_grow(struct cso_hash *hash)
{
if (hash->size >= hash->numBuckets)
cso_data_rehash(hash, hash->numBits + 1);
}
static void
cso_data_has_shrunk(struct cso_hash *hash)
{
if (hash->size <= (hash->numBuckets >> 3) &&
hash->numBits > hash->userNumBits) {
int max = MAX(hash->numBits-2, hash->userNumBits);
cso_data_rehash(hash, max);
}
}
static struct cso_node *
cso_data_first_node(struct cso_hash *hash)
{
struct cso_node *e = (struct cso_node *)hash;
struct cso_node **bucket = hash->buckets;
int n = hash->numBuckets;
while (n--) {
if (*bucket != e)
return *bucket;
++bucket;
}
return e;
}
struct cso_hash_iter
cso_hash_insert(struct cso_hash *hash, unsigned key, void *data)
{
cso_data_might_grow(hash);
struct cso_node **nextNode = cso_hash_find_node(hash, key);
struct cso_node *node = cso_hash_create_node(hash, key, data, nextNode);
if (!node) {
struct cso_hash_iter null_iter = {hash, NULL};
return null_iter;
}
struct cso_hash_iter iter = {hash, node};
return iter;
}
void
cso_hash_init(struct cso_hash *hash)
{
hash->fakeNext = NULL;
hash->buckets = NULL;
hash->size = 0;
hash->userNumBits = (short)MinNumBits;
hash->numBits = 0;
hash->numBuckets = 0;
hash->end = (struct cso_node*)hash;
}
void
cso_hash_deinit(struct cso_hash *hash)
{
struct cso_node *e_for_x = hash->end;
struct cso_node **bucket = hash->buckets;
int n = hash->numBuckets;
while (n--) {
struct cso_node *cur = *bucket++;
while (cur != e_for_x) {
struct cso_node *next = cur->next;
FREE(cur);
cur = next;
}
}
FREE(hash->buckets);
}
unsigned
cso_hash_iter_key(struct cso_hash_iter iter)
{
if (!iter.node || iter.hash->end == iter.node)
return 0;
return iter.node->key;
}
struct cso_node *
cso_hash_data_next(struct cso_node *node)
{
union {
struct cso_node *next;
struct cso_node *e;
struct cso_hash *d;
} a;
a.next = node->next;
if (!a.next) {
debug_printf("iterating beyond the last element\n");
return NULL;
}
if (a.next->next)
return a.next;
int start = (node->key % a.d->numBuckets) + 1;
struct cso_node **bucket = a.d->buckets + start;
int n = a.d->numBuckets - start;
while (n--) {
if (*bucket != a.e)
return *bucket;
++bucket;
}
return a.e;
}
void *
cso_hash_take(struct cso_hash *hash, unsigned akey)
{
struct cso_node **node = cso_hash_find_node(hash, akey);
if (*node != hash->end) {
void *t = (*node)->value;
struct cso_node *next = (*node)->next;
FREE(*node);
*node = next;
--hash->size;
cso_data_has_shrunk(hash);
return t;
}
return NULL;
}
struct cso_hash_iter
cso_hash_first_node(struct cso_hash *hash)
{
struct cso_hash_iter iter = {hash, cso_data_first_node(hash)};
return iter;
}
int
cso_hash_size(const struct cso_hash *hash)
{
return hash->size;
}
struct cso_hash_iter
cso_hash_erase(struct cso_hash *hash, struct cso_hash_iter iter)
{
struct cso_hash_iter ret = iter;
struct cso_node *node = iter.node;
struct cso_node **node_ptr;
if (node == hash->end)
return iter;
ret = cso_hash_iter_next(ret);
node_ptr = &hash->buckets[node->key % hash->numBuckets];
while (*node_ptr != node)
node_ptr = &(*node_ptr)->next;
*node_ptr = node->next;
FREE(node);
--hash->size;
return ret;
}
bool
cso_hash_contains(struct cso_hash *hash, unsigned key)
{
struct cso_node **node = cso_hash_find_node(hash, key);
return *node != hash->end;
}
+193
View File
@@ -0,0 +1,193 @@
/**************************************************************************
*
* Copyright 2007 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 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 ITS 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.
*
**************************************************************************/
/**
* @file
* Hash table implementation.
*
* This file provides a hash implementation that is capable of dealing
* with collisions. It stores colliding entries in linked list. All
* functions operating on the hash return an iterator. The iterator
* itself points to the collision list. If there wasn't any collision
* the list will have just one entry, otherwise client code should
* iterate over the entries to find the exact entry among ones that
* had the same key (e.g. memcmp could be used on the data to check
* that)
*
* @author Zack Rusin <[email protected]>
*/
#ifndef CSO_HASH_H
#define CSO_HASH_H
#include "util/compiler.h"
#ifdef __cplusplus
extern "C" {
#endif
struct cso_node {
struct cso_node *next;
void *value;
unsigned key;
};
struct cso_hash_iter {
struct cso_hash *hash;
struct cso_node *node;
};
struct cso_hash {
struct cso_node *fakeNext;
struct cso_node **buckets;
struct cso_node *end;
int size;
short userNumBits;
short numBits;
int numBuckets;
};
void
cso_hash_init(struct cso_hash *hash);
void
cso_hash_deinit(struct cso_hash *hash);
int
cso_hash_size(const struct cso_hash *hash);
/**
* Adds a data with the given key to the hash. If entry with the given
* key is already in the hash, this current entry is instered before it
* in the collision list.
* Function returns iterator pointing to the inserted item in the hash.
*/
struct cso_hash_iter
cso_hash_insert(struct cso_hash *hash, unsigned key, void *data);
/**
* Removes the item pointed to by the current iterator from the hash.
* Note that the data itself is not erased and if it was a malloc'ed pointer
* it will have to be freed after calling this function by the callee.
* Function returns iterator pointing to the item after the removed one in
* the hash.
*/
struct cso_hash_iter
cso_hash_erase(struct cso_hash *hash, struct cso_hash_iter iter);
void *
cso_hash_take(struct cso_hash *hash, unsigned key);
struct cso_hash_iter
cso_hash_first_node(struct cso_hash *hash);
/**
* Returns true if a value with the given key exists in the hash
*/
bool
cso_hash_contains(struct cso_hash *hash, unsigned key);
unsigned
cso_hash_iter_key(struct cso_hash_iter iter);
/**
* Convenience routine to iterate over the collision list while doing a memory
* comparison to see which entry in the list is a direct copy of our template
* and returns that entry.
*/
void *
cso_hash_find_data_from_template(struct cso_hash *hash,
unsigned hash_key,
void *templ,
int size);
struct cso_node *
cso_hash_data_next(struct cso_node *node);
static inline bool
cso_hash_iter_is_null(struct cso_hash_iter iter)
{
return !iter.node || iter.node == iter.hash->end;
}
static inline void *
cso_hash_iter_data(struct cso_hash_iter iter)
{
if (!iter.node || iter.hash->end == iter.node)
return NULL;
return iter.node->value;
}
static inline struct cso_node **
cso_hash_find_node(struct cso_hash *hash, unsigned akey)
{
struct cso_node **node;
if (hash->numBuckets) {
node = &hash->buckets[akey % hash->numBuckets];
assert(*node == hash->end || (*node)->next);
while (*node != hash->end && (*node)->key != akey)
node = &(*node)->next;
} else {
node = &hash->end;
}
return node;
}
/**
* Return an iterator pointing to the first entry in the collision list.
*/
static inline struct cso_hash_iter
cso_hash_find(struct cso_hash *hash, unsigned key)
{
struct cso_node **nextNode = cso_hash_find_node(hash, key);
struct cso_hash_iter iter = {hash, *nextNode};
return iter;
}
static inline struct cso_hash_iter
cso_hash_iter_next(struct cso_hash_iter iter)
{
struct cso_hash_iter next = {iter.hash, cso_hash_data_next(iter.node)};
return next;
}
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,199 @@
/**************************************************************************
*
* Copyright 2010, 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 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 ITS 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 "util/u_bitcast.h"
#include <math.h>
static bool
TAG(do_cliptest)(struct pt_post_vs *pvs,
struct draw_vertex_info *info,
const struct draw_prim_info *prim_info)
{
struct vertex_header *out = info->verts;
/* const */ float (*plane)[4] = pvs->draw->plane;
const unsigned pos = draw_current_shader_position_output(pvs->draw);
const unsigned cv = draw_current_shader_clipvertex_output(pvs->draw);
const unsigned ef = pvs->draw->vs.edgeflag_output;
unsigned ucp_enable = pvs->draw->rasterizer->clip_plane_enable;
unsigned flags = (FLAGS);
unsigned need_pipeline = 0;
bool have_cd = false;
bool uses_vp_idx = draw_current_shader_uses_viewport_index(pvs->draw);
unsigned viewport_index_output =
draw_current_shader_viewport_index_output(pvs->draw);
int viewport_index = 0;
int num_written_clipdistance =
draw_current_shader_num_written_clipdistances(pvs->draw);
if (uses_vp_idx) {
viewport_index = u_bitcast_f2u(out->data[viewport_index_output][0]);
viewport_index = draw_clamp_viewport_idx(viewport_index);
}
unsigned cd[2];
cd[0] = draw_current_shader_ccdistance_output(pvs->draw, 0);
cd[1] = draw_current_shader_ccdistance_output(pvs->draw, 1);
if (cd[0] != pos || cd[1] != pos)
have_cd = true;
/* If clipdistance semantic has been written by the shader
* that means we're expected to do 'user plane clipping' */
if (num_written_clipdistance && !(flags & DO_CLIP_USER)) {
flags |= DO_CLIP_USER;
ucp_enable = (1 << num_written_clipdistance) - 1;
}
assert(pos != -1);
unsigned prim_idx = 0, prim_vert_idx = 0;
for (unsigned j = 0; j < info->count; j++) {
float *position = out->data[pos];
unsigned mask = 0x0;
if (uses_vp_idx) {
/* only change the viewport_index for the leading vertex */
if (prim_vert_idx == (prim_info->primitive_lengths[prim_idx])) {
prim_idx++;
prim_vert_idx = 0;
viewport_index = u_bitcast_f2u(out->data[viewport_index_output][0]);
viewport_index = draw_clamp_viewport_idx(viewport_index);
}
prim_vert_idx++;
}
float *scale = pvs->draw->viewports[viewport_index].scale;
float *trans = pvs->draw->viewports[viewport_index].translate;
initialize_vertex_header(out);
if (flags & (DO_CLIP_XY | DO_CLIP_XY_GUARD_BAND |
DO_CLIP_FULL_Z | DO_CLIP_HALF_Z | DO_CLIP_USER)) {
float *clipvertex = position;
if ((flags & DO_CLIP_USER) && cv != pos) {
assert(cv != -1);
clipvertex = out->data[cv];
}
for (unsigned i = 0; i < 4; i++) {
out->clip_pos[i] = position[i];
}
/* Be careful with NaNs. Comparisons must be true for them. */
/* Do the hardwired planes first:
*/
if (flags & DO_CLIP_XY_GUARD_BAND) {
if (!(-0.50 * position[0] + position[3] >= 0)) mask |= (1<<0);
if (!( 0.50 * position[0] + position[3] >= 0)) mask |= (1<<1);
if (!(-0.50 * position[1] + position[3] >= 0)) mask |= (1<<2);
if (!( 0.50 * position[1] + position[3] >= 0)) mask |= (1<<3);
} else if (flags & DO_CLIP_XY) {
if (!(-position[0] + position[3] >= 0)) mask |= (1<<0);
if (!( position[0] + position[3] >= 0)) mask |= (1<<1);
if (!(-position[1] + position[3] >= 0)) mask |= (1<<2);
if (!( position[1] + position[3] >= 0)) mask |= (1<<3);
}
/* Clip Z planes according to full cube, half cube or none.
*/
if (flags & DO_CLIP_FULL_Z) {
if (!( position[2] + position[3] >= 0)) mask |= (1<<4);
if (!(-position[2] + position[3] >= 0)) mask |= (1<<5);
} else if (flags & DO_CLIP_HALF_Z) {
if (!( position[2] >= 0)) mask |= (1<<4);
if (!(-position[2] + position[3] >= 0)) mask |= (1<<5);
}
if (flags & DO_CLIP_USER) {
unsigned ucp_mask = ucp_enable;
while (ucp_mask) {
unsigned plane_idx = ffs(ucp_mask)-1;
ucp_mask &= ~(1 << plane_idx);
plane_idx += 6;
/*
* for user clipping check if we have a clip distance output
* and the shader has written to it, otherwise use clipvertex
* to decide when the plane is clipping.
*/
if (have_cd && num_written_clipdistance) {
float clipdist;
unsigned i = plane_idx - 6;
/* first four clip distance in first vector etc. */
if (i < 4)
clipdist = out->data[cd[0]][i];
else
clipdist = out->data[cd[1]][i-4];
if (clipdist < 0 || util_is_inf_or_nan(clipdist))
mask |= 1 << plane_idx;
} else {
if (!(dot4(clipvertex, plane[plane_idx]) >= 0))
mask |= 1 << plane_idx;
}
}
}
out->clipmask = mask;
need_pipeline |= out->clipmask;
}
/* For the window transformation, the first 4 (xy) clip planes should
* normally be handled by guardband clipping in clip_line_guard_xy, but
* it hasn't been fully implemented yet, so we'll have to do it here.
* Otherwise we'd skip it for being redundant.
*/
if (flags & DO_CLIP_XY_GUARD_BAND)
mask &= 0xfffffff0;
/*
* Transform the vertex position from clip coords to window coords,
* if the vertex is unclipped.
*/
if ((flags & DO_VIEWPORT) && mask == 0) {
/* divide by w */
float w = 1.0f / position[3];
/* Viewport mapping */
position[0] = position[0] * w * scale[0] + trans[0];
position[1] = position[1] * w * scale[1] + trans[1];
position[2] = position[2] * w * scale[2] + trans[2];
position[3] = w;
}
if ((flags & DO_EDGEFLAG) && ef) {
const float *edgeflag = out->data[ef];
out->edgeflag = !(edgeflag[0] != 1.0f);
need_pipeline |= !out->edgeflag;
}
out = (struct vertex_header *)((char *)out + info->stride);
}
return need_pipeline != 0;
}
#undef FLAGS
#undef TAG
File diff suppressed because it is too large. Load diff
+432
View File
@@ -0,0 +1,432 @@
/**************************************************************************
*
* Copyright 2007 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 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 ITS 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.
*
**************************************************************************/
/**
* \brief Public interface into the drawing module.
*/
/* Authors: Keith Whitwell <[email protected]>
*/
#ifndef DRAW_CONTEXT_H
#define DRAW_CONTEXT_H
#include "pipe/p_state.h"
#include "pipe/p_shader_tokens.h"
#include "util/mesa-blake3.h"
#include "nir.h"
struct pipe_context;
struct draw_context;
struct draw_stage;
struct draw_vertex_shader;
struct draw_geometry_shader;
struct draw_tess_ctrl_shader;
struct draw_tess_eval_shader;
struct draw_mesh_shader;
struct draw_fragment_shader;
struct tgsi_sampler;
struct tgsi_image;
struct tgsi_buffer;
struct lp_cached_code;
/*
* structure to contain driver internal information
* for stream out support. mapping stores the pointer
* to the buffer contents, and internal offset stores
* an internal counter to how much of the stream
* out buffer is used (in bytes).
*/
struct draw_so_target {
struct pipe_stream_output_target target;
void *mapping;
int internal_offset;
};
struct draw_vertex_info {
struct vertex_header *verts;
unsigned vertex_size;
unsigned stride;
unsigned count;
};
struct draw_prim_info {
bool linear;
unsigned start;
const uint16_t *elts;
unsigned count;
enum mesa_prim prim;
unsigned flags;
unsigned *primitive_lengths;
unsigned primitive_count;
};
struct draw_context *draw_create(struct pipe_context *pipe);
#if DRAW_LLVM_AVAILABLE
struct draw_context *draw_create_with_llvm_context(struct pipe_context *pipe,
void *context);
#endif
struct draw_context *draw_create_no_llvm(struct pipe_context *pipe);
void draw_destroy(struct draw_context *draw);
void draw_flush(struct draw_context *draw);
void draw_set_viewport_states(struct draw_context *draw,
unsigned start_slot,
unsigned num_viewports,
const struct pipe_viewport_state *viewports);
void draw_set_clip_state(struct draw_context *pipe,
const struct pipe_clip_state *clip);
/**
* Sets the rasterization state used by the draw module.
* The rast_handle is used to pass the driver specific representation
* of the rasterization state. It's going to be used when the
* draw module sets the state back on the driver itself using the
* pipe::bind_rasterizer_state method.
*
* NOTE: if you're calling this function from within the pipe's
* bind_rasterizer_state you should always call it before binding
* the actual state - that's because the draw module can try to
* bind its own rasterizer state which would reset your newly
* set state. i.e. always do
* draw_set_rasterizer_state(driver->draw, state->pipe_state, state);
* driver->state.raster = state;
*/
void draw_set_rasterizer_state(struct draw_context *draw,
const struct pipe_rasterizer_state *raster,
void *rast_handle);
void draw_set_rasterize_stage(struct draw_context *draw,
struct draw_stage *stage);
void draw_wide_point_threshold(struct draw_context *draw, float threshold);
void draw_wide_point_sprites(struct draw_context *draw, bool draw_sprite);
void draw_wide_line_threshold(struct draw_context *draw, float threshold);
void draw_enable_line_stipple(struct draw_context *draw, bool enable);
void draw_enable_point_sprites(struct draw_context *draw, bool enable);
void draw_set_zs_format(struct draw_context *draw, enum pipe_format format);
/* for TGSI constants are 4 * sizeof(float), but for NIR they need to be sizeof(float); */
void draw_set_constant_buffer_stride(struct draw_context *draw, unsigned num_bytes);
bool
draw_install_aaline_stage(struct draw_context *draw, struct pipe_context *pipe);
bool
draw_install_aapoint_stage(struct draw_context *draw, struct pipe_context *pipe,
nir_alu_type bool_type);
bool
draw_install_pstipple_stage(struct draw_context *draw, struct pipe_context *pipe);
struct tgsi_shader_info *
draw_get_shader_info(const struct draw_context *draw);
void
draw_prepare_shader_outputs(struct draw_context *draw);
int
draw_find_shader_output(const struct draw_context *draw,
enum tgsi_semantic semantic_name,
unsigned semantic_index);
bool
draw_will_inject_frontface(const struct draw_context *draw);
unsigned
draw_num_shader_outputs(const struct draw_context *draw);
unsigned
draw_total_vs_outputs(const struct draw_context *draw);
unsigned
draw_total_gs_outputs(const struct draw_context *draw);
unsigned
draw_total_tcs_outputs(const struct draw_context *draw);
unsigned
draw_total_tes_outputs(const struct draw_context *draw);
void
draw_texture_sampler(struct draw_context *draw,
mesa_shader_stage shader_type,
struct tgsi_sampler *sampler);
void
draw_image(struct draw_context *draw,
mesa_shader_stage shader_type,
struct tgsi_image *image);
void
draw_buffer(struct draw_context *draw,
mesa_shader_stage shader_type,
struct tgsi_buffer *buffer);
void
draw_set_sampler_views(struct draw_context *draw,
mesa_shader_stage shader_stage,
struct pipe_sampler_view **views,
unsigned num);
void
draw_set_samplers(struct draw_context *draw,
mesa_shader_stage shader_stage,
struct pipe_sampler_state **samplers,
unsigned num);
void
draw_set_images(struct draw_context *draw,
mesa_shader_stage shader_stage,
struct pipe_image_view *images,
unsigned num);
void
draw_set_mapped_texture(struct draw_context *draw,
mesa_shader_stage shader_stage,
unsigned sview_idx,
uint32_t width, uint32_t height, uint32_t depth,
uint32_t first_level, uint32_t last_level,
uint32_t num_samples,
uint32_t sample_stride,
const void *base,
uint32_t row_stride[PIPE_MAX_TEXTURE_LEVELS],
uint32_t img_stride[PIPE_MAX_TEXTURE_LEVELS],
uint32_t mip_offsets[PIPE_MAX_TEXTURE_LEVELS]);
void
draw_set_mapped_image(struct draw_context *draw,
mesa_shader_stage shader_stage,
unsigned idx,
uint32_t width, uint32_t height, uint32_t depth,
const void *base_ptr,
uint32_t row_stride,
uint32_t img_stride,
uint32_t num_samples,
uint32_t sample_stride);
/*
* Vertex shader functions
*/
struct draw_vertex_shader *
draw_create_vertex_shader(struct draw_context *draw,
const struct pipe_shader_state *shader);
void draw_bind_vertex_shader(struct draw_context *draw,
struct draw_vertex_shader *dvs);
void draw_delete_vertex_shader(struct draw_context *draw,
struct draw_vertex_shader *dvs);
void draw_vs_attach_so(struct draw_vertex_shader *dvs,
const struct pipe_stream_output_info *info);
void draw_vs_reset_so(struct draw_vertex_shader *dvs);
/*
* Fragment shader functions
*/
struct draw_fragment_shader *
draw_create_fragment_shader(struct draw_context *draw,
const struct pipe_shader_state *shader);
void draw_bind_fragment_shader(struct draw_context *draw,
struct draw_fragment_shader *dvs);
void draw_delete_fragment_shader(struct draw_context *draw,
struct draw_fragment_shader *dvs);
/*
* Geometry shader functions
*/
struct draw_geometry_shader *
draw_create_geometry_shader(struct draw_context *draw,
const struct pipe_shader_state *shader);
void draw_bind_geometry_shader(struct draw_context *draw,
struct draw_geometry_shader *dvs);
void draw_delete_geometry_shader(struct draw_context *draw,
struct draw_geometry_shader *dvs);
/*
* Tess shader functions
*/
struct draw_tess_ctrl_shader *
draw_create_tess_ctrl_shader(struct draw_context *draw,
const struct pipe_shader_state *shader);
void draw_bind_tess_ctrl_shader(struct draw_context *draw,
struct draw_tess_ctrl_shader *dvs);
void draw_delete_tess_ctrl_shader(struct draw_context *draw,
struct draw_tess_ctrl_shader *dvs);
struct draw_tess_eval_shader *
draw_create_tess_eval_shader(struct draw_context *draw,
const struct pipe_shader_state *shader);
void draw_bind_tess_eval_shader(struct draw_context *draw,
struct draw_tess_eval_shader *dvs);
void draw_delete_tess_eval_shader(struct draw_context *draw,
struct draw_tess_eval_shader *dvs);
void draw_set_tess_state(struct draw_context *draw,
const float default_outer_level[4],
const float default_inner_level[2]);
/*
* Mesh shader functions
*/
struct draw_mesh_shader *
draw_create_mesh_shader(struct draw_context *draw,
const struct pipe_shader_state *shader);
void draw_bind_mesh_shader(struct draw_context *draw,
struct draw_mesh_shader *dvs);
void draw_delete_mesh_shader(struct draw_context *draw,
struct draw_mesh_shader *dvs);
/*
* Vertex data functions
*/
void draw_set_vertex_buffers(struct draw_context *draw,
unsigned count,
const struct pipe_vertex_buffer *buffers);
void draw_set_vertex_elements(struct draw_context *draw,
unsigned count,
const struct pipe_vertex_element *elements);
void
draw_set_viewmask(struct draw_context *draw, uint8_t viewmask);
void draw_set_indexes(struct draw_context *draw,
const void *elements, unsigned elem_size,
unsigned available_space);
void draw_set_mapped_vertex_buffer(struct draw_context *draw,
unsigned attr, const void *buffer,
size_t size);
void
draw_set_mapped_constant_buffer(struct draw_context *draw,
mesa_shader_stage shader_type,
unsigned slot,
const void *buffer,
unsigned size);
void
draw_set_mapped_shader_buffer(struct draw_context *draw,
mesa_shader_stage shader_type,
unsigned slot,
const void *buffer,
unsigned size);
void
draw_set_mapped_so_targets(struct draw_context *draw,
unsigned num_targets,
struct draw_so_target *targets[PIPE_MAX_SO_BUFFERS]);
/***********************************************************************
* draw_pt.c
*/
void draw_vbo(struct draw_context *draw,
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,
uint8_t patch_vertices);
void
draw_mesh(struct draw_context *draw,
struct draw_vertex_info *vert_info,
struct draw_prim_info *prim_info);
/*******************************************************************************
* Driver backend interface
*/
struct vbuf_render;
void
draw_set_render(struct draw_context *draw,
struct vbuf_render *render);
void
draw_set_driver_clipping(struct draw_context *draw,
bool bypass_clip_xy,
bool bypass_clip_z,
bool guard_band_xy,
bool bypass_clip_points_lines);
/*******************************************************************************
* Draw statistics
*/
void
draw_collect_pipeline_statistics(struct draw_context *draw,
bool enable);
void
draw_collect_primitives_generated(struct draw_context *draw,
bool eanble);
/*******************************************************************************
* Draw pipeline
*/
bool
draw_need_pipeline(const struct draw_context *draw,
const struct pipe_rasterizer_state *rasterizer,
enum mesa_prim prim);
void
draw_init_shader_caps(struct pipe_shader_caps *caps);
bool
draw_get_option_use_llvm(void);
void
draw_set_disk_cache_callbacks(struct draw_context *draw,
void *data_cookie,
void (*find_shader)(void *cookie,
struct lp_cached_code *cache,
unsigned char ir_blake3_cache_key[BLAKE3_KEY_LEN]),
void (*insert_shader)(void *cookie,
struct lp_cached_code *cache,
unsigned char ir_blake3_cache_key[BLAKE3_KEY_LEN]));
#endif /* DRAW_CONTEXT_H */
@@ -0,0 +1,458 @@
/*
* Mesa 3-D graphics library
*
* Copyright 2008 VMware, Inc.
* Copyright (C) 2010 LunarG Inc.
*
* 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 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:
* Keith Whitwell <[email protected]>
* Chia-I Wu <[email protected]>
*/
/* these macros are optional */
#ifndef LOCAL_VARS
#define LOCAL_VARS
#endif
#ifndef FUNC_ENTER
#define FUNC_ENTER do {} while (0)
#endif
#ifndef FUNC_EXIT
#define FUNC_EXIT do {} while (0)
#endif
#ifndef LINE_ADJ
#define LINE_ADJ(flags, a0, i0, i1, a1) LINE(flags, i0, i1)
#endif
#ifndef TRIANGLE_ADJ
#define TRIANGLE_ADJ(flags, i0, a0, i1, a1, i2, a2) TRIANGLE(flags, i0, i1, i2)
#endif
static void
FUNC(FUNC_VARS)
{
unsigned idx[6], i;
uint16_t flags;
LOCAL_VARS
FUNC_ENTER;
/* prim, prim_flags, count, and last_vertex_last should have been defined */
if (0) {
debug_printf("%s: prim 0x%x, prim_flags 0x%x, count %d, last_vertex_last %d\n",
__func__, prim, prim_flags, count, last_vertex_last);
}
switch (prim) {
case MESA_PRIM_POINTS:
for (i = 0; i < count; i++) {
idx[0] = GET_ELT(i);
POINT(idx[0]);
}
break;
case MESA_PRIM_LINES:
flags = DRAW_PIPE_RESET_STIPPLE;
for (i = 0; i + 1 < count; i += 2) {
idx[0] = GET_ELT(i);
idx[1] = GET_ELT(i + 1);
LINE(flags, idx[0], idx[1]);
}
break;
case MESA_PRIM_LINE_LOOP:
case MESA_PRIM_LINE_STRIP:
if (count >= 2) {
flags = (prim_flags & DRAW_SPLIT_BEFORE) ? 0 : DRAW_PIPE_RESET_STIPPLE;
idx[1] = GET_ELT(0);
idx[2] = idx[1];
for (i = 1; i < count; i++, flags = 0) {
idx[0] = idx[1];
idx[1] = GET_ELT(i);
LINE(flags, idx[0], idx[1]);
}
/* close the loop */
if (prim == MESA_PRIM_LINE_LOOP && !prim_flags)
LINE(flags, idx[1], idx[2]);
}
break;
case MESA_PRIM_TRIANGLES:
flags = DRAW_PIPE_RESET_STIPPLE | DRAW_PIPE_EDGE_FLAG_ALL;
for (i = 0; i + 2 < count; i += 3) {
idx[0] = GET_ELT(i);
idx[1] = GET_ELT(i + 1);
idx[2] = GET_ELT(i + 2);
TRIANGLE(flags, idx[0], idx[1], idx[2]);
}
break;
case MESA_PRIM_TRIANGLE_STRIP:
if (count >= 3) {
flags = DRAW_PIPE_RESET_STIPPLE | DRAW_PIPE_EDGE_FLAG_ALL;
idx[1] = GET_ELT(0);
idx[2] = GET_ELT(1);
if (last_vertex_last) {
for (i = 0; i + 2 < count; i++) {
idx[0] = idx[1];
idx[1] = idx[2];
idx[2] = GET_ELT(i + 2);
/* always emit idx[2] last */
if (i & 1)
TRIANGLE(flags, idx[1], idx[0], idx[2]);
else
TRIANGLE(flags, idx[0], idx[1], idx[2]);
}
}
else {
for (i = 0; i + 2 < count; i++) {
idx[0] = idx[1];
idx[1] = idx[2];
idx[2] = GET_ELT(i + 2);
/* always emit idx[0] first */
if (i & 1)
TRIANGLE(flags, idx[0], idx[2], idx[1]);
else
TRIANGLE(flags, idx[0], idx[1], idx[2]);
}
}
}
break;
case MESA_PRIM_TRIANGLE_FAN:
if (count >= 3) {
flags = DRAW_PIPE_RESET_STIPPLE | DRAW_PIPE_EDGE_FLAG_ALL;
idx[0] = GET_ELT(0);
idx[2] = GET_ELT(1);
/* idx[0] is neither the first nor the last vertex */
if (last_vertex_last) {
for (i = 0; i + 2 < count; i++) {
idx[1] = idx[2];
idx[2] = GET_ELT(i + 2);
/* always emit idx[2] last */
TRIANGLE(flags, idx[0], idx[1], idx[2]);
}
}
else {
for (i = 0; i + 2 < count; i++) {
idx[1] = idx[2];
idx[2] = GET_ELT(i + 2);
/* always emit idx[1] first */
TRIANGLE(flags, idx[1], idx[2], idx[0]);
}
}
}
break;
case MESA_PRIM_QUADS:
if (last_vertex_last) {
for (i = 0; i + 3 < count; i += 4) {
idx[0] = GET_ELT(i);
idx[1] = GET_ELT(i + 1);
idx[2] = GET_ELT(i + 2);
idx[3] = GET_ELT(i + 3);
#ifdef PASS_QUADS
QUAD(0, idx[0], idx[1],
idx[2], idx[3]);
#else
flags = DRAW_PIPE_RESET_STIPPLE |
DRAW_PIPE_EDGE_FLAG_0 |
DRAW_PIPE_EDGE_FLAG_2;
/* always emit idx[3] last */
TRIANGLE(flags, idx[0], idx[1], idx[3]);
flags = DRAW_PIPE_EDGE_FLAG_0 |
DRAW_PIPE_EDGE_FLAG_1;
TRIANGLE(flags, idx[1], idx[2], idx[3]);
#endif
}
}
else {
for (i = 0; i + 3 < count; i += 4) {
idx[0] = GET_ELT(i);
idx[1] = GET_ELT(i + 1);
idx[2] = GET_ELT(i + 2);
idx[3] = GET_ELT(i + 3);
#ifdef PASS_QUADS
QUAD(0, idx[0], idx[1],
idx[2], idx[3]);
#else
flags = DRAW_PIPE_RESET_STIPPLE |
DRAW_PIPE_EDGE_FLAG_0 |
DRAW_PIPE_EDGE_FLAG_1;
/* always emit idx[3] / idx[0] first */
if (quads_flatshade_last)
TRIANGLE(flags, idx[3], idx[0], idx[1]);
else
TRIANGLE(flags, idx[0], idx[1], idx[2]);
flags = DRAW_PIPE_EDGE_FLAG_1 |
DRAW_PIPE_EDGE_FLAG_2;
if (quads_flatshade_last)
TRIANGLE(flags, idx[3], idx[1], idx[2]);
else
TRIANGLE(flags, idx[0], idx[2], idx[3]);
#endif
}
}
break;
case MESA_PRIM_QUAD_STRIP:
if (count >= 4) {
idx[2] = GET_ELT(0);
idx[3] = GET_ELT(1);
if (last_vertex_last) {
for (i = 0; i + 3 < count; i += 2) {
idx[0] = idx[2];
idx[1] = idx[3];
idx[2] = GET_ELT(i + 2);
idx[3] = GET_ELT(i + 3);
#ifdef PASS_QUADS
QUAD(0, idx[2], idx[0],
idx[1], idx[3]);
#else
/* always emit idx[3] last */
flags = DRAW_PIPE_RESET_STIPPLE |
DRAW_PIPE_EDGE_FLAG_0 |
DRAW_PIPE_EDGE_FLAG_2;
TRIANGLE(flags, idx[2], idx[0], idx[3]);
flags = DRAW_PIPE_EDGE_FLAG_0 |
DRAW_PIPE_EDGE_FLAG_1;
TRIANGLE(flags, idx[0], idx[1], idx[3]);
#endif
}
}
else {
for (i = 0; i + 3 < count; i += 2) {
idx[0] = idx[2];
idx[1] = idx[3];
idx[2] = GET_ELT(i + 2);
idx[3] = GET_ELT(i + 3);
#ifdef PASS_QUADS
QUAD(0, idx[3], idx[2],
idx[0], idx[1]);
#else
flags = DRAW_PIPE_RESET_STIPPLE |
DRAW_PIPE_EDGE_FLAG_0 |
DRAW_PIPE_EDGE_FLAG_1;
/* always emit idx[3] / idx[0 first */
if (quads_flatshade_last)
TRIANGLE(flags, idx[3], idx[2], idx[0]);
else
TRIANGLE(flags, idx[0], idx[3], idx[2]);
flags = DRAW_PIPE_EDGE_FLAG_1 |
DRAW_PIPE_EDGE_FLAG_2;
if (quads_flatshade_last)
TRIANGLE(flags, idx[3], idx[0], idx[1]);
else
TRIANGLE(flags, idx[0], idx[1], idx[3]);
#endif
}
}
}
break;
case MESA_PRIM_POLYGON:
if (count >= 3) {
uint16_t edge_next, edge_finish;
if (last_vertex_last) {
flags = (DRAW_PIPE_RESET_STIPPLE |
DRAW_PIPE_EDGE_FLAG_0);
if (!(prim_flags & DRAW_SPLIT_BEFORE))
flags |= DRAW_PIPE_EDGE_FLAG_2;
edge_next = DRAW_PIPE_EDGE_FLAG_0;
edge_finish =
(prim_flags & DRAW_SPLIT_AFTER) ? 0 : DRAW_PIPE_EDGE_FLAG_1;
}
else {
flags = (DRAW_PIPE_RESET_STIPPLE |
DRAW_PIPE_EDGE_FLAG_1);
if (!(prim_flags & DRAW_SPLIT_BEFORE))
flags |= DRAW_PIPE_EDGE_FLAG_0;
edge_next = DRAW_PIPE_EDGE_FLAG_1;
edge_finish =
(prim_flags & DRAW_SPLIT_AFTER) ? 0 : DRAW_PIPE_EDGE_FLAG_2;
}
idx[0] = GET_ELT(0);
idx[2] = GET_ELT(1);
for (i = 0; i + 2 < count; i++, flags = edge_next) {
idx[1] = idx[2];
idx[2] = GET_ELT(i + 2);
if (i + 3 == count)
flags |= edge_finish;
/* idx[0] is both the first and the last vertex */
if (last_vertex_last)
TRIANGLE(flags, idx[1], idx[2], idx[0]);
else
TRIANGLE(flags, idx[0], idx[1], idx[2]);
}
}
break;
case MESA_PRIM_LINES_ADJACENCY:
flags = DRAW_PIPE_RESET_STIPPLE;
for (i = 0; i + 3 < count; i += 4) {
idx[0] = GET_ELT(i);
idx[1] = GET_ELT(i + 1);
idx[2] = GET_ELT(i + 2);
idx[3] = GET_ELT(i + 3);
LINE_ADJ(flags, idx[0], idx[1], idx[2], idx[3]);
}
break;
case MESA_PRIM_LINE_STRIP_ADJACENCY:
if (count >= 4) {
flags = (prim_flags & DRAW_SPLIT_BEFORE) ? 0 : DRAW_PIPE_RESET_STIPPLE;
idx[1] = GET_ELT(0);
idx[2] = GET_ELT(1);
idx[3] = GET_ELT(2);
for (i = 1; i + 2 < count; i++, flags = 0) {
idx[0] = idx[1];
idx[1] = idx[2];
idx[2] = idx[3];
idx[3] = GET_ELT(i + 2);
LINE_ADJ(flags, idx[0], idx[1], idx[2], idx[3]);
}
}
break;
case MESA_PRIM_TRIANGLES_ADJACENCY:
flags = DRAW_PIPE_RESET_STIPPLE | DRAW_PIPE_EDGE_FLAG_ALL;
for (i = 0; i + 5 < count; i += 6) {
idx[0] = GET_ELT(i);
idx[1] = GET_ELT(i + 1);
idx[2] = GET_ELT(i + 2);
idx[3] = GET_ELT(i + 3);
idx[4] = GET_ELT(i + 4);
idx[5] = GET_ELT(i + 5);
TRIANGLE_ADJ(flags, idx[0], idx[1], idx[2], idx[3], idx[4], idx[5]);
}
break;
case MESA_PRIM_TRIANGLE_STRIP_ADJACENCY:
if (count >= 6) {
flags = DRAW_PIPE_RESET_STIPPLE | DRAW_PIPE_EDGE_FLAG_ALL;
idx[0] = GET_ELT(1);
idx[2] = GET_ELT(0);
idx[4] = GET_ELT(2);
idx[3] = GET_ELT(4);
/*
* The vertices of the i-th triangle are stored in
* idx[0,2,4] = { 2*i, 2*i+2, 2*i+4 };
*
* The adjacent vertices are stored in
* idx[1,3,5] = { 2*i-2, 2*i+6, 2*i+3 }.
*
* However, there are two exceptions:
*
* For the first triangle, idx[1] = 1;
* For the last triangle, idx[3] = 2*i+5.
*/
if (last_vertex_last) {
for (i = 0; i + 5 < count; i += 2) {
idx[1] = idx[0];
idx[0] = idx[2];
idx[2] = idx[4];
idx[4] = idx[3];
idx[3] = GET_ELT(i + ((i + 7 < count) ? 6 : 5));
idx[5] = GET_ELT(i + 3);
/*
* alternate the first two vertices (idx[0] and idx[2]) and the
* corresponding adjacent vertices (idx[3] and idx[5]) to have
* the correct orientation
*/
if (i & 2) {
TRIANGLE_ADJ(flags,
idx[2], idx[1], idx[0], idx[5], idx[4], idx[3]);
}
else {
TRIANGLE_ADJ(flags,
idx[0], idx[1], idx[2], idx[3], idx[4], idx[5]);
}
}
}
else {
for (i = 0; i + 5 < count; i += 2) {
idx[1] = idx[0];
idx[0] = idx[2];
idx[2] = idx[4];
idx[4] = idx[3];
idx[3] = GET_ELT(i + ((i + 7 < count) ? 6 : 5));
idx[5] = GET_ELT(i + 3);
/*
* alternate the last two vertices (idx[2] and idx[4]) and the
* corresponding adjacent vertices (idx[1] and idx[5]) to have
* the correct orientation
*/
if (i & 2) {
TRIANGLE_ADJ(flags,
idx[0], idx[5], idx[4], idx[3], idx[2], idx[1]);
}
else {
TRIANGLE_ADJ(flags,
idx[0], idx[1], idx[2], idx[3], idx[4], idx[5]);
}
}
}
}
break;
default:
assert(0);
break;
}
FUNC_EXIT;
}
#undef LOCAL_VARS
#undef FUNC_ENTER
#undef FUNC_EXIT
#undef LINE_ADJ
#undef TRIANGLE_ADJ
#undef FUNC
#undef FUNC_VARS
#undef GET_ELT
#undef POINT
#undef LINE
#undef TRIANGLE
+76
View File
@@ -0,0 +1,76 @@
/**************************************************************************
*
* Copyright 2010 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 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 ITS 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 "pipe/p_shader_tokens.h"
#include "util/u_math.h"
#include "util/u_memory.h"
#include "util/u_prim.h"
#include "nir/nir_to_tgsi_info.h"
#include "draw_fs.h"
#include "draw_private.h"
#include "draw_context.h"
struct draw_fragment_shader *
draw_create_fragment_shader(struct draw_context *draw,
const struct pipe_shader_state *shader)
{
struct draw_fragment_shader *dfs;
dfs = CALLOC_STRUCT(draw_fragment_shader);
if (dfs) {
dfs->base = *shader;
if (shader->type == PIPE_SHADER_IR_TGSI)
tgsi_scan_shader(shader->tokens, &dfs->info);
else
nir_tgsi_scan_shader(shader->ir.nir, &dfs->info, true);
}
return dfs;
}
void
draw_bind_fragment_shader(struct draw_context *draw,
struct draw_fragment_shader *dfs)
{
draw_do_flush(draw, DRAW_FLUSH_STATE_CHANGE);
draw->fs.fragment_shader = dfs;
}
void
draw_delete_fragment_shader(struct draw_context *draw,
struct draw_fragment_shader *dfs)
{
FREE(dfs);
}
+42
View File
@@ -0,0 +1,42 @@
/**************************************************************************
*
* Copyright 2010 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 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 ITS 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 DRAW_FS_H
#define DRAW_FS_H
#include "tgsi/tgsi_scan.h"
struct draw_fragment_shader
{
struct pipe_shader_state base;
struct tgsi_shader_info info;
};
#endif /* DRAW_FS_H */
File diff suppressed because it is too large. Load diff
+165
View File
@@ -0,0 +1,165 @@
/**************************************************************************
*
* 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 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 ITS 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 DRAW_GS_H
#define DRAW_GS_H
#include "draw_context.h"
#include "tgsi/tgsi_exec.h"
#include "tgsi/tgsi_scan.h"
#include "draw_private.h"
#define MAX_TGSI_PRIMITIVES 4
struct draw_context;
#if DRAW_LLVM_AVAILABLE
struct draw_gs_jit_context;
struct draw_gs_llvm_variant;
/**
* Structure holding the inputs to the geometry shader. It uses SOA layout.
* The dimensions are as follows:
* - maximum number of vertices for a geometry shader input primitive
* (6 for triangle_adjacency)
* - maximum number of attributes for each vertex
* - four channels per each attribute (x,y,z,w)
* - number of input primitives equal to the SOA vector length
*/
struct draw_gs_inputs {
float data[6][PIPE_MAX_SHADER_INPUTS][TGSI_NUM_CHANNELS][TGSI_NUM_CHANNELS];
};
#endif
/**
* Private version of the compiled geometry shader
*/
struct draw_vertex_stream {
unsigned *primitive_lengths;
unsigned emitted_vertices;
unsigned emitted_primitives;
float (*tmp_output)[4];
};
struct draw_geometry_shader {
struct draw_context *draw;
struct tgsi_exec_machine *machine;
/* This member will disappear shortly:*/
struct pipe_shader_state state;
struct tgsi_shader_info info;
unsigned position_output;
unsigned viewport_index_output;
unsigned clipvertex_output;
unsigned ccdistance_output[PIPE_MAX_CLIP_OR_CULL_DISTANCE_ELEMENT_COUNT];
unsigned max_output_vertices;
unsigned primitive_boundary;
enum mesa_prim input_primitive;
enum mesa_prim output_primitive;
unsigned vertex_size;
struct draw_vertex_stream stream[TGSI_MAX_VERTEX_STREAMS];
unsigned num_vertex_streams;
unsigned in_prim_idx;
unsigned tess_prim_idx;
const uint32_t *next_patch_length;
unsigned input_vertex_stride;
unsigned fetched_prim_count;
const float (*input)[4];
const struct tgsi_shader_info *input_info;
unsigned vector_length;
unsigned max_out_prims;
unsigned num_invocations;
unsigned invocation_id;
#if DRAW_LLVM_AVAILABLE
struct draw_gs_inputs *gs_input;
struct draw_gs_jit_context *jit_context;
struct lp_jit_resources *jit_resources;
struct draw_gs_llvm_variant *current_variant;
struct vertex_header *gs_output[PIPE_MAX_VERTEX_STREAMS];
int **llvm_prim_lengths;
int *llvm_emitted_primitives;
int *llvm_emitted_vertices;
int *llvm_prim_ids;
#endif
void (*fetch_inputs)(struct draw_geometry_shader *shader,
unsigned *indices,
unsigned num_vertices,
unsigned prim_idx);
void (*fetch_outputs)(struct draw_geometry_shader *shader,
unsigned vertex_stream,
unsigned num_primitives,
float (**p_output)[4]);
void (*prepare)(struct draw_geometry_shader *shader,
const struct draw_buffer_info *constants);
void (*run)(struct draw_geometry_shader *shader,
unsigned input_primitives, unsigned *out_prims);
};
void
draw_geometry_shader_new_instance(struct draw_geometry_shader *gs);
/*
* Returns the number of vertices emitted.
* The vertex shader can emit any number of vertices as long as it's
* smaller than the GS_MAX_OUTPUT_VERTICES shader property.
*/
void
draw_geometry_shader_run(struct draw_geometry_shader *shader,
const struct draw_buffer_info *constants,
const struct draw_vertex_info *input_verts,
const struct draw_prim_info *input_prim,
const struct tgsi_shader_info *input_info,
uint32_t *const *patch_lengths,
struct draw_vertex_info *output_verts,
struct draw_prim_info *output_prims);
void
draw_geometry_shader_prepare(struct draw_geometry_shader *shader,
struct draw_context *draw);
int
draw_gs_max_output_vertices(struct draw_geometry_shader *shader,
unsigned pipe_prim);
#if DRAW_LLVM_AVAILABLE
void
draw_gs_set_current_variant(struct draw_geometry_shader *shader,
struct draw_gs_llvm_variant *variant);
#endif
#endif
+32
View File
@@ -0,0 +1,32 @@
#define FUNC_VARS struct draw_geometry_shader *gs, \
const struct draw_prim_info *input_prims, \
const struct draw_vertex_info *input_verts, \
struct draw_prim_info *output_prims, \
struct draw_vertex_info *output_verts
#define FUNC_ENTER \
/* declare more local vars */ \
const unsigned prim = input_prims->prim; \
const unsigned prim_flags = input_prims->flags; \
const unsigned count = input_prims->count; \
const bool quads_flatshade_last = false; \
const bool last_vertex_last = !gs->draw->rasterizer->flatshade_first; \
do { \
switch (prim) { \
case MESA_PRIM_QUADS: \
case MESA_PRIM_QUAD_STRIP: \
case MESA_PRIM_POLYGON: \
assert(!"unexpected primitive type in GS"); \
return; \
default: \
break; \
} \
} while (0)
#define POINT(i0) gs_point(gs,i0)
#define LINE(flags,i0,i1) gs_line(gs,i0,i1)
#define TRIANGLE(flags,i0,i1,i2) gs_tri(gs,i0,i1,i2)
#define LINE_ADJ(flags,i0,i1,i2,i3) gs_line_adj(gs,i0,i1,i2,i3)
#define TRIANGLE_ADJ(flags,i0,i1,i2,i3,i4,i5) gs_tri_adj(gs,i0,i1,i2,i3,i4,i5)
#define QUAD(flags,i0,i1,i2,i3)
#include "draw_decompose_tmp.h"
File diff suppressed because it is too large. Load diff
+693
View File
@@ -0,0 +1,693 @@
/**************************************************************************
*
* Copyright 2010 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 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 ITS 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 DRAW_LLVM_H
#define DRAW_LLVM_H
#include "draw/draw_private.h"
#include "draw/draw_vs.h"
#include "draw/draw_gs.h"
#include "draw/draw_tess.h"
#include "gallivm/lp_bld.h"
#include "gallivm/lp_bld_sample.h"
#include "gallivm/lp_bld_jit_types.h"
#include "gallivm/lp_bld_jit_sample.h"
#include "pipe/p_context.h"
#include "util/list.h"
struct draw_llvm;
struct llvm_vertex_shader;
struct llvm_geometry_shader;
struct llvm_tess_ctrl_shader;
struct llvm_tess_eval_shader;
/**
* This structure is passed directly to the generated vertex shader.
*
* It contains the derived state.
*
* Changes here must be reflected in the draw_jit_context_* macros.
* Changes to the ordering should be avoided.
*
* Only use types with a clear size and padding here, in particular prefer the
* stdint.h types to the basic integer types.
*/
struct draw_vs_jit_context
{
float (*planes) [DRAW_TOTAL_CLIP_PLANES][4];
struct pipe_viewport_state *viewports;
};
enum {
DRAW_VS_JIT_CTX_PLANES = 0,
DRAW_VS_JIT_CTX_VIEWPORT = 1,
DRAW_VS_JIT_CTX_NUM_FIELDS
};
#define draw_vs_jit_context_planes(_gallivm, _type, _ptr) \
lp_build_struct_get2(_gallivm, _type, _ptr, DRAW_VS_JIT_CTX_PLANES, "planes")
#define draw_vs_jit_context_viewports(_variant, _ptr) \
lp_build_struct_get2(_variant->gallivm, _variant->context_type, _ptr, DRAW_VS_JIT_CTX_VIEWPORT, "viewports")
#define draw_jit_vbuffer_offset(_gallivm, _type, _ptr) \
lp_build_struct_get2(_gallivm, _type, _ptr, 1, "buffer_offset")
enum {
DRAW_JIT_DVBUFFER_MAP = 0,
DRAW_JIT_DVBUFFER_SIZE,
DRAW_JIT_DVBUFFER_NUM_FIELDS /* number of fields above */
};
#define draw_jit_dvbuffer_map(_gallivm, _type, _ptr) \
lp_build_struct_get2(_gallivm, _type, _ptr, DRAW_JIT_DVBUFFER_MAP, "map")
#define draw_jit_dvbuffer_size(_gallivm, _type, _ptr) \
lp_build_struct_get2(_gallivm, _type, _ptr, DRAW_JIT_DVBUFFER_SIZE, "size")
/**
* This structure is passed directly to the generated geometry shader.
*
* It contains the derived state.
*
* Changes here must be reflected in the draw_gs_jit_context_* macros.
* Changes to the ordering should be avoided.
*
* Only use types with a clear size and padding here, in particular prefer the
* stdint.h types to the basic integer types.
*/
struct draw_gs_jit_context
{
float (*planes) [DRAW_TOTAL_CLIP_PLANES][4];
struct pipe_viewport_state *viewports;
int **prim_lengths;
int *emitted_vertices;
int *emitted_prims;
};
enum {
DRAW_GS_JIT_CTX_PLANES = 0,
DRAW_GS_JIT_CTX_VIEWPORT = 1,
DRAW_GS_JIT_CTX_PRIM_LENGTHS = 2,
DRAW_GS_JIT_CTX_EMITTED_VERTICES = 3,
DRAW_GS_JIT_CTX_EMITTED_PRIMS = 4,
DRAW_GS_JIT_CTX_NUM_FIELDS = 5
};
#define draw_gs_jit_context_planes(_gallivm, _ptr) \
lp_build_struct_get(_gallivm, _ptr, DRAW_GS_JIT_CTX_PLANES, "planes")
#define draw_gs_jit_context_viewports(_gallivm, _ptr) \
lp_build_struct_get(_gallivm, _ptr, DRAW_GS_JIT_CTX_VIEWPORT, "viewports")
#define draw_gs_jit_prim_lengths(_variant, _ptr) \
lp_build_struct_get2(_variant->gallivm, _variant->context_type, _ptr, DRAW_GS_JIT_CTX_PRIM_LENGTHS, "prim_lengths")
#define draw_gs_jit_emitted_vertices(_variant, _ptr) \
lp_build_struct_get2(_variant->gallivm, _variant->context_type, _ptr, DRAW_GS_JIT_CTX_EMITTED_VERTICES, "emitted_vertices")
#define draw_gs_jit_emitted_prims(_variant, _ptr) \
lp_build_struct_get2(_variant->gallivm, _variant->context_type, _ptr, DRAW_GS_JIT_CTX_EMITTED_PRIMS, "emitted_prims")
typedef bool
(*draw_jit_vert_func)(struct draw_vs_jit_context *context,
const struct lp_jit_resources *resources,
struct vertex_header *io,
const struct draw_vertex_buffer vbuffers[PIPE_MAX_ATTRIBS],
unsigned count,
unsigned start,
unsigned stride,
struct pipe_vertex_buffer *vertex_buffers,
unsigned instance_id,
unsigned vertex_id_offset,
unsigned start_instance,
const unsigned *fetch_elts,
unsigned draw_id, unsigned view_id);
typedef int
(*draw_gs_jit_func)(struct draw_gs_jit_context *context,
const struct lp_jit_resources *resources,
float inputs[6][PIPE_MAX_SHADER_INPUTS][TGSI_NUM_CHANNELS][TGSI_NUM_CHANNELS],
struct vertex_header **output,
unsigned num_prims,
unsigned instance_id,
int *prim_ids,
unsigned invocation_id,
unsigned view_id);
typedef int
(*draw_tcs_jit_func)(const struct lp_jit_resources *resources,
float inputs[32][NUM_TCS_INPUTS][TGSI_NUM_CHANNELS],
float outputs[32][PIPE_MAX_SHADER_INPUTS][TGSI_NUM_CHANNELS],
uint32_t prim_id, uint32_t patch_vertices_in,
unsigned view_id);
typedef int
(*draw_tes_jit_func)(const struct lp_jit_resources *resources,
float inputs[32][PIPE_MAX_SHADER_INPUTS][TGSI_NUM_CHANNELS],
struct vertex_header *io,
uint32_t prim_id, uint32_t num_tess_coord,
float *tess_coord_x, float *tess_coord_y, float *tess_outer,
float *tess_inner, uint32_t patch_vertices_in,
unsigned view_id);
struct draw_llvm_variant_key
{
unsigned nr_vertex_elements:8;
unsigned nr_samplers:8;
unsigned nr_sampler_views:8;
unsigned nr_images:8;
unsigned clamp_vertex_color:1;
unsigned clip_xy:1;
unsigned clip_z:1;
unsigned clip_user:1;
unsigned clip_halfz:1;
unsigned bypass_viewport:1;
unsigned need_edgeflags:1;
unsigned has_gs_or_tes:1;
unsigned num_outputs:8;
unsigned ucp_enable:PIPE_MAX_CLIP_PLANES;
/* note padding here - must use memset */
/* Variable number of vertex elements:
*/
struct pipe_vertex_element vertex_element[1];
/* Followed by variable number of samplers:
*/
/* struct draw_sampler_static_state sampler; */
/* Followed by variable number of images
*/
};
struct draw_gs_llvm_variant_key
{
unsigned nr_samplers:8;
unsigned nr_sampler_views:8;
unsigned nr_images:8;
unsigned num_outputs:8;
/* note padding here - must use memset */
unsigned clamp_vertex_color:1;
struct lp_sampler_static_state samplers[1];
/* Followed by variable number of images.*/
};
struct draw_tcs_llvm_variant_key
{
unsigned nr_samplers:8;
unsigned nr_sampler_views:8;
unsigned nr_images:8;
struct lp_sampler_static_state samplers[1];
/* Followed by variable number of images.*/
};
struct draw_tes_llvm_variant_key
{
unsigned nr_samplers:8;
unsigned nr_sampler_views:8;
unsigned nr_images:8;
unsigned primid_output:7;
unsigned primid_needed:1;
unsigned clamp_vertex_color:1;
struct lp_sampler_static_state samplers[1];
/* Followed by variable number of images.*/
};
#define DRAW_LLVM_MAX_VARIANT_KEY_SIZE \
(sizeof(struct draw_llvm_variant_key) + \
PIPE_MAX_SHADER_SAMPLER_VIEWS * sizeof(struct lp_sampler_static_state) + \
PIPE_MAX_SHADER_IMAGES * sizeof(struct lp_image_static_state) + \
(PIPE_MAX_ATTRIBS-1) * sizeof(struct pipe_vertex_element))
#define DRAW_GS_LLVM_MAX_VARIANT_KEY_SIZE \
(sizeof(struct draw_gs_llvm_variant_key) + \
PIPE_MAX_SHADER_IMAGES * sizeof(struct lp_image_static_state) + \
PIPE_MAX_SHADER_SAMPLER_VIEWS * sizeof(struct lp_sampler_static_state))
#define DRAW_TCS_LLVM_MAX_VARIANT_KEY_SIZE \
(sizeof(struct draw_tcs_llvm_variant_key) + \
PIPE_MAX_SHADER_IMAGES * sizeof(struct lp_image_static_state) + \
PIPE_MAX_SHADER_SAMPLER_VIEWS * sizeof(struct lp_sampler_static_state))
#define DRAW_TES_LLVM_MAX_VARIANT_KEY_SIZE \
(sizeof(struct draw_tes_llvm_variant_key) + \
PIPE_MAX_SHADER_IMAGES * sizeof(struct lp_image_static_state) + \
PIPE_MAX_SHADER_SAMPLER_VIEWS * sizeof(struct lp_sampler_static_state))
static inline size_t
draw_llvm_variant_key_size(unsigned nr_vertex_elements,
unsigned nr_samplers,
unsigned nr_sampler_views,
unsigned nr_images)
{
return (sizeof(struct draw_llvm_variant_key) +
(nr_vertex_elements - 1) * sizeof(struct pipe_vertex_element) +
MAX2(nr_samplers, nr_sampler_views) *
sizeof(struct lp_sampler_static_state) +
nr_images * sizeof(struct lp_image_static_state));
}
static inline size_t
draw_gs_llvm_variant_key_size(unsigned nr_samplers,
unsigned nr_sampler_views,
unsigned nr_images)
{
return (sizeof(struct draw_gs_llvm_variant_key) +
(MAX2(nr_samplers, nr_sampler_views) - 1) *
sizeof(struct lp_sampler_static_state) +
nr_images * sizeof(struct lp_sampler_static_state));
}
static inline size_t
draw_tcs_llvm_variant_key_size(unsigned nr_samplers,
unsigned nr_sampler_views,
unsigned nr_images)
{
return (sizeof(struct draw_tcs_llvm_variant_key) +
(MAX2(nr_samplers, nr_sampler_views) - 1) *
sizeof(struct lp_sampler_static_state) +
nr_images * sizeof(struct lp_sampler_static_state));
}
static inline size_t
draw_tes_llvm_variant_key_size(unsigned nr_samplers,
unsigned nr_sampler_views,
unsigned nr_images)
{
return (sizeof(struct draw_tes_llvm_variant_key) +
(MAX2(nr_samplers, nr_sampler_views) - 1) *
sizeof(struct lp_sampler_static_state) +
nr_images * sizeof(struct lp_sampler_static_state));
}
static inline struct lp_sampler_static_state *
draw_llvm_variant_key_samplers(struct draw_llvm_variant_key *key)
{
return (struct lp_sampler_static_state *)
&key->vertex_element[key->nr_vertex_elements];
}
static inline struct lp_image_static_state *
draw_llvm_variant_key_images(struct draw_llvm_variant_key *key)
{
struct lp_sampler_static_state *samplers = (struct lp_sampler_static_state *)
(&key->vertex_element[key->nr_vertex_elements]);
return (struct lp_image_static_state *)
&samplers[MAX2(key->nr_samplers, key->nr_sampler_views)];
}
static inline struct lp_image_static_state *
draw_gs_llvm_variant_key_images(struct draw_gs_llvm_variant_key *key)
{
return (struct lp_image_static_state *)
&key->samplers[MAX2(key->nr_samplers, key->nr_sampler_views)];
}
static inline struct lp_image_static_state *
draw_tcs_llvm_variant_key_images(struct draw_tcs_llvm_variant_key *key)
{
return (struct lp_image_static_state *)
&key->samplers[MAX2(key->nr_samplers, key->nr_sampler_views)];
}
static inline struct lp_image_static_state *
draw_tes_llvm_variant_key_images(struct draw_tes_llvm_variant_key *key)
{
return (struct lp_image_static_state *)
&key->samplers[MAX2(key->nr_samplers, key->nr_sampler_views)];
}
struct draw_llvm_variant_list_item
{
struct list_head list;
struct draw_llvm_variant *base;
};
struct draw_gs_llvm_variant_list_item
{
struct list_head list;
struct draw_gs_llvm_variant *base;
};
struct draw_tcs_llvm_variant_list_item
{
struct list_head list;
struct draw_tcs_llvm_variant *base;
};
struct draw_tes_llvm_variant_list_item
{
struct list_head list;
struct draw_tes_llvm_variant *base;
};
struct draw_llvm_variant
{
struct gallivm_state *gallivm;
/* LLVM JIT builder types */
LLVMTypeRef context_type;
LLVMTypeRef context_ptr_type;
LLVMTypeRef resources_type;
LLVMTypeRef resources_ptr_type;
LLVMTypeRef buffer_type;
LLVMTypeRef buffer_ptr_type;
LLVMTypeRef vb_type;
LLVMTypeRef vb_ptr_type;
LLVMTypeRef vertex_header_type;
LLVMTypeRef vertex_header_ptr_type;
LLVMValueRef function;
char *function_name;
draw_jit_vert_func jit_func;
struct llvm_vertex_shader *shader;
struct draw_llvm *llvm;
struct draw_llvm_variant_list_item list_item_global;
struct draw_llvm_variant_list_item list_item_local;
/* key is variable-sized, must be last */
struct draw_llvm_variant_key key;
};
struct draw_gs_llvm_variant
{
struct gallivm_state *gallivm;
/* LLVM JIT builder types */
LLVMTypeRef context_type;
LLVMTypeRef context_ptr_type;
LLVMTypeRef resources_type;
LLVMTypeRef resources_ptr_type;
LLVMTypeRef vertex_header_type;
LLVMTypeRef vertex_header_ptr_type;
LLVMTypeRef input_array_type;
LLVMValueRef context_ptr;
LLVMValueRef io_ptr;
LLVMValueRef num_prims;
LLVMValueRef function;
char *function_name;
draw_gs_jit_func jit_func;
struct llvm_geometry_shader *shader;
struct draw_llvm *llvm;
struct draw_gs_llvm_variant_list_item list_item_global;
struct draw_gs_llvm_variant_list_item list_item_local;
/* key is variable-sized, must be last */
struct draw_gs_llvm_variant_key key;
};
struct draw_tcs_llvm_variant
{
struct gallivm_state *gallivm;
/* LLVM JIT builder types */
LLVMTypeRef resources_type;
LLVMTypeRef resources_ptr_type;
LLVMTypeRef input_array_type;
LLVMTypeRef output_array_type;
LLVMValueRef context_ptr;
/* LLVMValueRef io_ptr; */
LLVMValueRef num_prims;
LLVMValueRef function;
char *function_name;
draw_tcs_jit_func jit_func;
struct llvm_tess_ctrl_shader *shader;
struct draw_llvm *llvm;
struct draw_tcs_llvm_variant_list_item list_item_global;
struct draw_tcs_llvm_variant_list_item list_item_local;
/* key is variable-sized, must be last */
struct draw_tcs_llvm_variant_key key;
};
struct draw_tes_llvm_variant
{
struct gallivm_state *gallivm;
/* LLVM JIT builder types */
LLVMTypeRef resources_type;
LLVMTypeRef resources_ptr_type;
LLVMTypeRef vertex_header_ptr_type;
LLVMTypeRef input_array_type;
LLVMTypeRef patch_input_array_type;
LLVMTypeRef input_array_deref_type;
LLVMTypeRef vertex_header_type;
LLVMValueRef context_ptr;
LLVMValueRef io_ptr;
LLVMValueRef num_prims;
LLVMValueRef function;
char *function_name;
draw_tes_jit_func jit_func;
struct llvm_tess_eval_shader *shader;
struct draw_llvm *llvm;
struct draw_tes_llvm_variant_list_item list_item_global;
struct draw_tes_llvm_variant_list_item list_item_local;
/* key is variable-sized, must be last */
struct draw_tes_llvm_variant_key key;
};
struct llvm_vertex_shader {
struct draw_vertex_shader base;
unsigned variant_key_size;
struct draw_llvm_variant_list_item variants;
unsigned variants_created;
unsigned variants_cached;
};
struct llvm_geometry_shader {
struct draw_geometry_shader base;
unsigned variant_key_size;
struct draw_gs_llvm_variant_list_item variants;
unsigned variants_created;
unsigned variants_cached;
};
struct llvm_tess_ctrl_shader {
struct draw_tess_ctrl_shader base;
unsigned variant_key_size;
struct draw_tcs_llvm_variant_list_item variants;
unsigned variants_created;
unsigned variants_cached;
};
struct llvm_tess_eval_shader {
struct draw_tess_eval_shader base;
unsigned variant_key_size;
struct draw_tes_llvm_variant_list_item variants;
unsigned variants_created;
unsigned variants_cached;
};
struct draw_llvm {
struct draw_context *draw;
lp_context_ref context;
struct draw_vs_jit_context vs_jit_context;
struct draw_gs_jit_context gs_jit_context;
struct lp_jit_resources jit_resources[DRAW_MAX_SHADER_STAGE];
struct draw_llvm_variant_list_item vs_variants_list;
int nr_variants;
struct draw_gs_llvm_variant_list_item gs_variants_list;
int nr_gs_variants;
struct draw_tcs_llvm_variant_list_item tcs_variants_list;
int nr_tcs_variants;
struct draw_tes_llvm_variant_list_item tes_variants_list;
int nr_tes_variants;
};
static inline struct llvm_vertex_shader *
llvm_vertex_shader(struct draw_vertex_shader *vs)
{
return (struct llvm_vertex_shader *)vs;
}
static inline struct llvm_geometry_shader *
llvm_geometry_shader(struct draw_geometry_shader *gs)
{
return (struct llvm_geometry_shader *)gs;
}
static inline struct llvm_tess_ctrl_shader *
llvm_tess_ctrl_shader(struct draw_tess_ctrl_shader *tcs)
{
return (struct llvm_tess_ctrl_shader *)tcs;
}
static inline struct llvm_tess_eval_shader *
llvm_tess_eval_shader(struct draw_tess_eval_shader *tes)
{
return (struct llvm_tess_eval_shader *)tes;
}
struct draw_llvm *
draw_llvm_create(struct draw_context *draw, lp_context_ref *llvm_context);
void
draw_llvm_destroy(struct draw_llvm *llvm);
struct draw_llvm_variant *
draw_llvm_create_variant(struct draw_llvm *llvm,
unsigned num_vertex_header_attribs,
const struct draw_llvm_variant_key *key);
void
draw_llvm_destroy_variant(struct draw_llvm_variant *variant);
struct draw_llvm_variant_key *
draw_llvm_make_variant_key(struct draw_llvm *llvm, char *store);
void
draw_llvm_dump_variant_key(struct draw_llvm_variant_key *key);
struct draw_gs_llvm_variant *
draw_gs_llvm_create_variant(struct draw_llvm *llvm,
unsigned num_vertex_header_attribs,
const struct draw_gs_llvm_variant_key *key);
void
draw_gs_llvm_destroy_variant(struct draw_gs_llvm_variant *variant);
struct draw_gs_llvm_variant_key *
draw_gs_llvm_make_variant_key(struct draw_llvm *llvm, char *store);
void
draw_gs_llvm_dump_variant_key(struct draw_gs_llvm_variant_key *key);
struct draw_tcs_llvm_variant *
draw_tcs_llvm_create_variant(struct draw_llvm *llvm,
unsigned num_vertex_header_attribs,
const struct draw_tcs_llvm_variant_key *key);
void
draw_tcs_llvm_destroy_variant(struct draw_tcs_llvm_variant *variant);
struct draw_tcs_llvm_variant_key *
draw_tcs_llvm_make_variant_key(struct draw_llvm *llvm, char *store);
void
draw_tcs_llvm_dump_variant_key(struct draw_tcs_llvm_variant_key *key);
struct draw_tes_llvm_variant *
draw_tes_llvm_create_variant(struct draw_llvm *llvm,
unsigned num_vertex_header_attribs,
const struct draw_tes_llvm_variant_key *key);
void
draw_tes_llvm_destroy_variant(struct draw_tes_llvm_variant *variant);
struct draw_tes_llvm_variant_key *
draw_tes_llvm_make_variant_key(struct draw_llvm *llvm, char *store);
void
draw_tes_llvm_dump_variant_key(struct draw_tes_llvm_variant_key *key);
void
draw_llvm_set_sampler_state(struct draw_context *draw,
mesa_shader_stage shader_stage);
void
draw_llvm_set_mapped_texture(struct draw_context *draw,
mesa_shader_stage shader_stage,
unsigned sview_idx,
uint32_t width, uint32_t height, uint32_t depth,
uint32_t first_level, uint32_t last_level,
uint32_t num_samples,
uint32_t sample_stride,
const void *base_ptr,
uint32_t row_stride[PIPE_MAX_TEXTURE_LEVELS],
uint32_t img_stride[PIPE_MAX_TEXTURE_LEVELS],
uint32_t mip_offsets[PIPE_MAX_TEXTURE_LEVELS]);
void
draw_llvm_set_mapped_image(struct draw_context *draw,
mesa_shader_stage shader_stage,
unsigned idx,
uint32_t width, uint32_t height, uint32_t depth,
const void *base_ptr,
uint32_t row_stride,
uint32_t img_stride,
uint32_t num_samples,
uint32_t sample_stride);
void
draw_store_aos_array(struct gallivm_state *gallivm,
struct lp_type soa_type,
LLVMTypeRef io_type,
LLVMValueRef io_ptr,
LLVMValueRef *indices,
LLVMValueRef* aos,
int attrib,
LLVMValueRef clipmask,
bool need_edgeflag,
bool per_prim);
#endif
+101
View File
@@ -0,0 +1,101 @@
/**************************************************************************
*
* Copyright 2023 Red Hat.
* 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
* 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 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.
*
**************************************************************************/
#include "draw_mesh.h"
#include "draw_context.h"
#include "tgsi/tgsi_scan.h"
#include "nir/nir_to_tgsi_info.h"
#include "pipe/p_shader_tokens.h"
struct draw_mesh_shader *
draw_create_mesh_shader(struct draw_context *draw,
const struct pipe_shader_state *state)
{
struct draw_mesh_shader *ms;
ms = CALLOC_STRUCT(draw_mesh_shader);
if (!ms)
return NULL;
ms->draw = draw;
nir_tgsi_scan_shader(state->ir.nir, &ms->info, true);
nir_shader *nir = state->ir.nir;
ms->output_primitive = nir->info.mesh.primitive_type;
ms->position_output = -1;
bool found_clipvertex = false;
for (unsigned i = 0; i < ms->info.num_outputs; i++) {
if (ms->info.output_semantic_name[i] == TGSI_SEMANTIC_POSITION &&
ms->info.output_semantic_index[i] == 0)
ms->position_output = i;
if (ms->info.output_semantic_name[i] == TGSI_SEMANTIC_VIEWPORT_INDEX)
ms->viewport_index_output = i;
if (ms->info.output_semantic_name[i] == TGSI_SEMANTIC_CLIPVERTEX &&
ms->info.output_semantic_index[i] == 0) {
found_clipvertex = true;
ms->clipvertex_output = i;
}
if (ms->info.output_semantic_name[i] == TGSI_SEMANTIC_CLIPDIST) {
assert(ms->info.output_semantic_index[i] <
PIPE_MAX_CLIP_OR_CULL_DISTANCE_ELEMENT_COUNT);
ms->ccdistance_output[ms->info.output_semantic_index[i]] = i;
}
}
if (!found_clipvertex)
ms->clipvertex_output = ms->position_output;
return ms;
}
void
draw_bind_mesh_shader(struct draw_context *draw,
struct draw_mesh_shader *dms)
{
draw_do_flush(draw, DRAW_FLUSH_STATE_CHANGE);
if (dms) {
draw->ms.mesh_shader = dms;
draw->ms.num_ms_outputs = dms->info.num_outputs;
draw->ms.position_output = dms->position_output;
draw->ms.clipvertex_output = dms->clipvertex_output;
} else {
draw->ms.mesh_shader = NULL;
draw->ms.num_ms_outputs = 0;
}
}
void
draw_delete_mesh_shader(struct draw_context *draw,
struct draw_mesh_shader *dms)
{
if (!dms)
return;
FREE(dms);
}
+48
View File
@@ -0,0 +1,48 @@
/**************************************************************************
*
* Copyright 2023 Red Hat.
* 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
* 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 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.
*
**************************************************************************/
#ifndef DRAW_MESH_H
#define DRAW_MESH_H
#include "draw_context.h"
#include "draw_private.h"
#include "tgsi/tgsi_exec.h"
#include "tgsi/tgsi_scan.h"
struct draw_context;
struct draw_mesh_shader {
struct draw_context *draw;
struct tgsi_shader_info info;
unsigned position_output;
unsigned viewport_index_output;
unsigned clipvertex_output;
unsigned ccdistance_output[PIPE_MAX_CLIP_OR_CULL_DISTANCE_ELEMENT_COUNT];
unsigned output_primitive;
};
#endif
+229
View File
@@ -0,0 +1,229 @@
/**************************************************************************
*
* Copyright 2023 Red Hat.
* 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
* 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 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.
*
**************************************************************************/
/*
* Mesh primitive assembler
*
* This takes vertex and per-primitive data, and assembles a linear set
* of draw compatible vertices.
*/
#include "draw_mesh_prim.h"
#include "draw/draw_context.h"
#include "draw/draw_private.h"
#include "util/u_debug.h"
#include "util/u_memory.h"
#include "pipe/p_defines.h"
struct draw_mesh_prim
{
struct draw_context *draw;
struct draw_prim_info *output_prims;
struct draw_vertex_info *output_verts;
const struct draw_prim_info *input_prims;
const struct draw_vertex_info *input_verts;
unsigned num_prims;
const char *per_prim;
uint32_t num_per_prim;
uint32_t added_prim_size;
int cull_prim_idx;
};
static void
add_prim(struct draw_mesh_prim *asmblr, unsigned length)
{
struct draw_prim_info *output_prims = asmblr->output_prims;
output_prims->primitive_lengths = realloc(output_prims->primitive_lengths, sizeof(unsigned) * (output_prims->primitive_count + 1));
output_prims->primitive_lengths[output_prims->primitive_count] = length;
output_prims->primitive_count++;
}
/*
* Copy the vertex header along with its data from the current
* vertex buffer into a buffer holding vertices arranged
* into decomposed primitives (i.e. buffer without the
* adjacency vertices)
*/
static void
copy_verts(struct draw_mesh_prim *asmblr,
unsigned *indices, unsigned num_indices)
{
char *output = (char*)asmblr->output_verts->verts;
const char *input = (const char*)asmblr->input_verts->verts;
for (unsigned i = 0; i < num_indices; ++i) {
unsigned idx = indices[i];
unsigned output_offset =
asmblr->output_verts->count * asmblr->output_verts->stride;
unsigned input_offset = asmblr->input_verts->stride * idx;
memcpy(output + output_offset, input + input_offset,
asmblr->input_verts->vertex_size);
memcpy(output + output_offset + asmblr->input_verts->vertex_size,
asmblr->per_prim + (asmblr->num_prims * asmblr->added_prim_size * 8),
asmblr->added_prim_size);
asmblr->output_verts->count += 1;
}
++asmblr->num_prims;
}
static bool
cull_prim(struct draw_mesh_prim *asmblr)
{
if (asmblr->cull_prim_idx == -1)
return false;
const uint32_t *cull_prim_ptr = (uint32_t *)(asmblr->per_prim + (asmblr->num_prims * asmblr->added_prim_size * 8));
cull_prim_ptr += (asmblr->cull_prim_idx * 4);
return (*cull_prim_ptr) ? true : false;
}
static void
prim_point(struct draw_mesh_prim *asmblr,
unsigned idx)
{
unsigned indices[1];
indices[0] = idx;
if (cull_prim(asmblr)) {
++asmblr->num_prims;
return;
}
add_prim(asmblr, 1);
copy_verts(asmblr, indices, 1);
}
static void
prim_line(struct draw_mesh_prim *asmblr,
unsigned i0, unsigned i1)
{
unsigned indices[2];
indices[0] = i0;
indices[1] = i1;
if (cull_prim(asmblr)) {
++asmblr->num_prims;
return;
}
add_prim(asmblr, 2);
copy_verts(asmblr, indices, 2);
}
static void
prim_tri(struct draw_mesh_prim *asmblr,
unsigned i0, unsigned i1, unsigned i2)
{
unsigned indices[3];
indices[0] = i0;
indices[1] = i1;
indices[2] = i2;
if (cull_prim(asmblr)) {
++asmblr->num_prims;
return;
}
add_prim(asmblr, 3);
copy_verts(asmblr, indices, 3);
}
#define FUNC assembler_run_linear
#define GET_ELT(idx) (start + (idx))
#include "draw_mesh_prim_tmp.h"
#define FUNC assembler_run_elts
#define LOCAL_VARS const uint16_t *elts = input_prims->elts;
#define GET_ELT(idx) (elts[start + (idx)])
#include "draw_mesh_prim_tmp.h"
void
draw_mesh_prim_run(struct draw_context *draw,
unsigned num_per_prim_inputs,
void *per_prim_inputs,
int cull_prim_idx,
const struct draw_prim_info *input_prims,
const struct draw_vertex_info *input_verts,
struct draw_prim_info *output_prims,
struct draw_vertex_info *output_verts)
{
struct draw_mesh_prim asmblr_mesh;
struct draw_mesh_prim *asmblr = &asmblr_mesh;
unsigned start, i;
unsigned max_primitives = input_prims->primitive_count;
unsigned max_verts = mesa_vertices_per_prim(input_prims->prim) * max_primitives;
asmblr->output_prims = output_prims;
asmblr->output_verts = output_verts;
asmblr->input_prims = input_prims;
asmblr->input_verts = input_verts;
asmblr->num_prims = 0;
asmblr->num_per_prim = num_per_prim_inputs;
asmblr->per_prim = per_prim_inputs;
asmblr->cull_prim_idx = cull_prim_idx;
output_prims->linear = true;
output_prims->elts = NULL;
output_prims->start = 0;
output_prims->prim = input_prims->prim;
output_prims->flags = 0x0;
output_prims->primitive_lengths = MALLOC(sizeof(unsigned));
output_prims->primitive_lengths[0] = 0;
output_prims->primitive_count = 0;
asmblr->added_prim_size = asmblr->num_per_prim * (4 * sizeof(float));
output_verts->vertex_size = input_verts->vertex_size + asmblr->added_prim_size;
output_verts->stride = output_verts->vertex_size;
output_verts->verts = (struct vertex_header*)MALLOC(
output_verts->vertex_size * max_verts);
output_verts->count = 0;
for (start = i = 0; i < input_prims->primitive_count;
start += input_prims->primitive_lengths[i], i++) {
unsigned count = input_prims->primitive_lengths[i];
if (input_prims->linear) {
assembler_run_linear(asmblr, input_prims, input_verts,
start, count);
} else {
assembler_run_elts(asmblr, input_prims, input_verts,
start, count);
}
}
output_prims->count = output_verts->count;
}
@@ -0,0 +1,42 @@
/**************************************************************************
*
* Copyright 2023 Red Hat.
* 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
* 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 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.
*
**************************************************************************/
#ifndef DRAW_MESH_PRIM_H
#define DRAW_MESH_PRIM_H
struct draw_context;
struct draw_prim_info;
struct draw_vertex_info;
void
draw_mesh_prim_run(struct draw_context *draw,
unsigned num_per_prim_inputs,
void *per_prim_inputs,
int cull_prim_idx,
const struct draw_prim_info *in_prim_info,
const struct draw_vertex_info *in_vert_info,
struct draw_prim_info *out_prim_info,
struct draw_vertex_info *out_vert_info);
#endif
@@ -0,0 +1,30 @@
#define FUNC_VARS \
struct draw_mesh_prim *asmblr, \
const struct draw_prim_info *input_prims, \
const struct draw_vertex_info *input_verts, \
unsigned start, \
unsigned count
#define FUNC_ENTER \
/* declare more local vars */ \
const enum mesa_prim prim = input_prims->prim; \
const unsigned prim_flags = input_prims->flags; \
const bool last_vertex_last = false; \
switch (prim) { \
case MESA_PRIM_POINTS: \
case MESA_PRIM_LINES: \
case MESA_PRIM_TRIANGLES: \
break; \
default: \
assert(!"unexpected primitive type in prim assembler"); \
return; \
}
#define POINT(i0) prim_point(asmblr, i0)
#define LINE(flags, i0, i1) prim_line(asmblr, i0, i1)
#define TRIANGLE(flags, i0, i1, i2) prim_tri(asmblr, i0, i1, i2)
#define QUAD(flags, i0, i1, i2, i3)
#define PASS_QUADS
#include "draw_decompose_tmp.h"
+357
View File
@@ -0,0 +1,357 @@
/**************************************************************************
*
* Copyright 2007 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 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 ITS 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.
*
**************************************************************************/
/*
* Authors:
* Keith Whitwell <[email protected]>
*/
#include "draw/draw_private.h"
#include "draw/draw_pipe.h"
#include "util/u_debug.h"
#include "util/u_math.h"
bool
draw_pipeline_init(struct draw_context *draw)
{
/* create pipeline stages */
draw->pipeline.wide_line = draw_wide_line_stage(draw);
draw->pipeline.wide_point = draw_wide_point_stage(draw);
draw->pipeline.stipple = draw_stipple_stage(draw);
draw->pipeline.unfilled = draw_unfilled_stage(draw);
draw->pipeline.twoside = draw_twoside_stage(draw);
draw->pipeline.offset = draw_offset_stage(draw);
draw->pipeline.clip = draw_clip_stage(draw);
draw->pipeline.flatshade = draw_flatshade_stage(draw);
draw->pipeline.cull = draw_cull_stage(draw);
draw->pipeline.user_cull = draw_user_cull_stage(draw);
draw->pipeline.validate = draw_validate_stage(draw);
draw->pipeline.first = draw->pipeline.validate;
if (!draw->pipeline.wide_line ||
!draw->pipeline.wide_point ||
!draw->pipeline.stipple ||
!draw->pipeline.unfilled ||
!draw->pipeline.twoside ||
!draw->pipeline.offset ||
!draw->pipeline.clip ||
!draw->pipeline.flatshade ||
!draw->pipeline.cull ||
!draw->pipeline.user_cull ||
!draw->pipeline.validate)
return false;
/* these defaults are oriented toward the needs of softpipe */
draw->pipeline.wide_point_threshold = 1000000.0f; /* infinity */
draw->pipeline.wide_line_threshold = 1.0f;
draw->pipeline.wide_point_sprites = false;
draw->pipeline.line_stipple = true;
draw->pipeline.point_sprite = true;
return true;
}
void
draw_pipeline_destroy(struct draw_context *draw)
{
if (draw->pipeline.wide_line)
draw->pipeline.wide_line->destroy(draw->pipeline.wide_line);
if (draw->pipeline.wide_point)
draw->pipeline.wide_point->destroy(draw->pipeline.wide_point);
if (draw->pipeline.stipple)
draw->pipeline.stipple->destroy(draw->pipeline.stipple);
if (draw->pipeline.unfilled)
draw->pipeline.unfilled->destroy(draw->pipeline.unfilled);
if (draw->pipeline.twoside)
draw->pipeline.twoside->destroy(draw->pipeline.twoside);
if (draw->pipeline.offset)
draw->pipeline.offset->destroy(draw->pipeline.offset);
if (draw->pipeline.clip)
draw->pipeline.clip->destroy(draw->pipeline.clip);
if (draw->pipeline.flatshade)
draw->pipeline.flatshade->destroy(draw->pipeline.flatshade);
if (draw->pipeline.cull)
draw->pipeline.cull->destroy(draw->pipeline.cull);
if (draw->pipeline.user_cull)
draw->pipeline.user_cull->destroy(draw->pipeline.user_cull);
if (draw->pipeline.validate)
draw->pipeline.validate->destroy(draw->pipeline.validate);
if (draw->pipeline.aaline)
draw->pipeline.aaline->destroy(draw->pipeline.aaline);
if (draw->pipeline.aapoint)
draw->pipeline.aapoint->destroy(draw->pipeline.aapoint);
if (draw->pipeline.pstipple)
draw->pipeline.pstipple->destroy(draw->pipeline.pstipple);
if (draw->pipeline.rasterize)
draw->pipeline.rasterize->destroy(draw->pipeline.rasterize);
}
/**
* Build primitive to render a point with vertex at v0.
*/
static void
do_point(struct draw_context *draw,
const char *v0)
{
struct prim_header prim;
prim.flags = 0;
prim.pad = 0;
prim.v[0] = (struct vertex_header *)v0;
draw->pipeline.first->point(draw->pipeline.first, &prim);
}
/**
* Build primitive to render a line with vertices at v0, v1.
* \param flags bitmask of DRAW_PIPE_EDGE_x, DRAW_PIPE_RESET_STIPPLE
*/
static void
do_line(struct draw_context *draw,
uint16_t flags,
const char *v0,
const char *v1)
{
struct prim_header prim;
prim.flags = flags;
prim.pad = 0;
prim.v[0] = (struct vertex_header *)v0;
prim.v[1] = (struct vertex_header *)v1;
draw->pipeline.first->line(draw->pipeline.first, &prim);
}
/**
* Build primitive to render a triangle with vertices at v0, v1, v2.
* \param flags bitmask of DRAW_PIPE_EDGE_x, DRAW_PIPE_RESET_STIPPLE
*/
static void
do_triangle(struct draw_context *draw,
uint16_t flags,
char *v0,
char *v1,
char *v2)
{
struct prim_header prim;
prim.v[0] = (struct vertex_header *)v0;
prim.v[1] = (struct vertex_header *)v1;
prim.v[2] = (struct vertex_header *)v2;
prim.flags = flags;
prim.pad = 0;
draw->pipeline.first->tri(draw->pipeline.first, &prim);
}
/*
* Set up macros for draw_pt_decompose.h template code.
* This code uses vertex indexes / elements.
*/
#define TRIANGLE(flags,i0,i1,i2) \
do { \
do_triangle(draw, \
flags, \
verts + stride * (i0), \
verts + stride * (i1), \
verts + stride * (i2)); \
} while (0)
#define LINE(flags,i0,i1) \
do { \
do_line(draw, \
flags, \
verts + stride * (i0), \
verts + stride * (i1)); \
} while (0)
#define POINT(i0) \
do { \
do_point(draw, verts + stride * (i0)); \
} while (0)
#define GET_ELT(idx) (MIN2(elts[idx], max_index))
#define FUNC pipe_run_elts
#define FUNC_VARS \
struct draw_context *draw, \
enum mesa_prim prim, \
unsigned prim_flags, \
struct vertex_header *vertices, \
unsigned stride, \
const uint16_t *elts, \
unsigned count, \
unsigned max_index
#include "draw_pt_decompose.h"
/**
* Code to run the pipeline on a fairly arbitrary collection of vertices.
* For drawing indexed primitives.
*
* Vertex headers must be pre-initialized with the
* UNDEFINED_VERTEX_ID, this code will cause that id to become
* overwritten, so it may have to be reset if there is the intention
* to reuse the vertices.
*
* This code provides a callback to reset the vertex id's which the
* draw_vbuf.c code uses when it has to perform a flush.
*/
void
draw_pipeline_run(struct draw_context *draw,
const struct draw_vertex_info *vert_info,
const struct draw_prim_info *prim_info)
{
draw->pipeline.verts = (char *)vert_info->verts;
draw->pipeline.vertex_stride = vert_info->stride;
draw->pipeline.vertex_count = vert_info->count;
unsigned i, start;
for (start = i = 0;
i < prim_info->primitive_count;
start += prim_info->primitive_lengths[i], i++) {
const unsigned count = prim_info->primitive_lengths[i];
#if MESA_DEBUG
/* Warn if one of the element indexes go outside the vertex buffer */
{
unsigned max_index = 0x0;
/* find the largest element index */
for (unsigned i = 0; i < count; i++) {
unsigned int index = prim_info->elts[start + i];
if (index > max_index)
max_index = index;
}
if (max_index >= vert_info->count) {
debug_printf("%s: max_index (%u) outside vertex buffer (%u)\n",
__func__,
max_index,
vert_info->count);
}
}
#endif
pipe_run_elts(draw,
prim_info->prim,
prim_info->flags,
vert_info->verts,
vert_info->stride,
prim_info->elts + start,
count,
vert_info->count - 1);
}
draw->pipeline.verts = NULL;
draw->pipeline.vertex_count = 0;
}
/*
* Set up macros for draw_pt_decompose.h template code.
* This code is for non-indexed (aka linear) rendering (no elts).
*/
#define TRIANGLE(flags,i0,i1,i2) \
do_triangle(draw, flags, \
verts + stride * (i0), \
verts + stride * (i1), \
verts + stride * (i2))
#define LINE(flags,i0,i1) \
do_line(draw, flags, \
verts + stride * (i0), \
verts + stride * (i1))
#define POINT(i0) \
do_point(draw, verts + stride * (i0))
#define GET_ELT(idx) (idx)
#define FUNC pipe_run_linear
#define FUNC_VARS \
struct draw_context *draw, \
enum mesa_prim prim, \
unsigned prim_flags, \
struct vertex_header *vertices, \
unsigned stride, \
unsigned count
#include "draw_pt_decompose.h"
/*
* For drawing non-indexed primitives.
*/
void
draw_pipeline_run_linear(struct draw_context *draw,
const struct draw_vertex_info *vert_info,
const struct draw_prim_info *prim_info)
{
for (unsigned start = 0, i = 0;
i < prim_info->primitive_count;
start += prim_info->primitive_lengths[i], i++) {
unsigned count = prim_info->primitive_lengths[i];
char *verts = ((char*)vert_info->verts) +
(start * vert_info->stride);
draw->pipeline.verts = verts;
draw->pipeline.vertex_stride = vert_info->stride;
draw->pipeline.vertex_count = count;
assert(count <= vert_info->count);
pipe_run_linear(draw,
prim_info->prim,
prim_info->flags,
(struct vertex_header*)verts,
vert_info->stride,
count);
}
draw->pipeline.verts = NULL;
draw->pipeline.vertex_count = 0;
}
void
draw_pipeline_flush(struct draw_context *draw,
unsigned flags)
{
draw->pipeline.first->flush(draw->pipeline.first, flags);
if (flags & DRAW_FLUSH_STATE_CHANGE)
draw->pipeline.first = draw->pipeline.validate;
}
+128
View File
@@ -0,0 +1,128 @@
/**************************************************************************
*
* Copyright 2007 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 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 ITS 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.
*
**************************************************************************/
/*
* Authors:
* Keith Whitwell <[email protected]>
*/
#ifndef DRAW_PIPE_H
#define DRAW_PIPE_H
#include "util/compiler.h"
#include "draw_private.h" /* for sizeof(vertex_header) */
#include "draw_context.h"
/**
* Basic info for a point/line/triangle primitive.
*/
struct prim_header {
float det; /**< front/back face determinant */
uint16_t flags;
uint16_t pad;
struct vertex_header *v[3]; /**< 1 to 3 vertex pointers */
};
/**
* Base class for all primitive drawing stages.
*/
struct draw_stage
{
struct draw_context *draw; /**< parent context */
struct draw_stage *next; /**< next stage in pipeline */
const char *name; /**< for debugging */
struct vertex_header **tmp; /**< temp vert storage, such as for clipping */
unsigned nr_tmps;
void (*point)(struct draw_stage *, struct prim_header *);
void (*line)(struct draw_stage *, struct prim_header *);
void (*tri)(struct draw_stage *, struct prim_header *);
void (*flush)(struct draw_stage *, unsigned flags);
void (*reset_stipple_counter)(struct draw_stage *);
void (*destroy)(struct draw_stage *);
};
struct draw_stage *draw_unfilled_stage(struct draw_context *context);
struct draw_stage *draw_twoside_stage(struct draw_context *context);
struct draw_stage *draw_offset_stage(struct draw_context *context);
struct draw_stage *draw_clip_stage(struct draw_context *context);
struct draw_stage *draw_flatshade_stage(struct draw_context *context);
struct draw_stage *draw_cull_stage(struct draw_context *context);
struct draw_stage *draw_user_cull_stage(struct draw_context *draw);
struct draw_stage *draw_stipple_stage(struct draw_context *context);
struct draw_stage *draw_wide_line_stage(struct draw_context *context);
struct draw_stage *draw_wide_point_stage(struct draw_context *context);
struct draw_stage *draw_validate_stage(struct draw_context *context);
void draw_free_temp_verts(struct draw_stage *stage);
bool draw_alloc_temp_verts(struct draw_stage *stage, unsigned nr);
void draw_reset_vertex_ids(struct draw_context *draw);
void draw_pipe_passthrough_tri(struct draw_stage *stage, struct prim_header *header);
void draw_pipe_passthrough_line(struct draw_stage *stage, struct prim_header *header);
void draw_pipe_passthrough_point(struct draw_stage *stage, struct prim_header *header);
void draw_aapoint_prepare_outputs(struct draw_context *context,
struct draw_stage *stage);
void draw_aaline_prepare_outputs(struct draw_context *context,
struct draw_stage *stage);
void draw_unfilled_prepare_outputs(struct draw_context *context,
struct draw_stage *stage);
/**
* Get a writeable copy of a vertex.
* \param stage drawing stage info
* \param vert the vertex to copy (source)
* \param idx index into stage's tmp[] array to put the copy (dest)
* \return pointer to the copied vertex
*/
static inline struct vertex_header *
dup_vert(struct draw_stage *stage,
const struct vertex_header *vert,
unsigned idx)
{
struct vertex_header *tmp = stage->tmp[idx];
const unsigned vsize = sizeof(struct vertex_header)
+ draw_num_shader_outputs(stage->draw) * 4 * sizeof(float);
memcpy(tmp, vert, vsize);
tmp->vertex_id = UNDEFINED_VERTEX_ID;
return tmp;
}
#endif
@@ -0,0 +1,763 @@
/**************************************************************************
*
* Copyright 2007-2018 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 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 ITS 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.
*
**************************************************************************/
/**
* AA line stage: AA lines are converted triangles (with extra generic)
*
* Authors: Brian Paul
*/
#include "pipe/p_context.h"
#include "pipe/p_defines.h"
#include "pipe/p_shader_tokens.h"
#include "util/u_inlines.h"
#include "util/format/u_format.h"
#include "util/u_math.h"
#include "util/u_memory.h"
#include "tgsi/tgsi_transform.h"
#include "tgsi/tgsi_dump.h"
#include "draw_context.h"
#include "draw_private.h"
#include "draw_pipe.h"
#include "nir.h"
#include "nir/nir_draw_helpers.h"
/** Approx number of new tokens for instructions in aa_transform_inst() */
#define NUM_NEW_TOKENS 53
/**
* Subclass of pipe_shader_state to carry extra fragment shader info.
*/
struct aaline_fragment_shader
{
struct pipe_shader_state state;
void *driver_fs;
void *aaline_fs;
int generic_attrib; /**< generic used for distance */
};
/**
* Subclass of draw_stage
*/
struct aaline_stage
{
struct draw_stage stage;
float half_line_width;
/** For AA lines, this is the vertex attrib slot for new generic */
unsigned coord_slot;
/** position, not necessarily output zero */
unsigned pos_slot;
/*
* Currently bound state
*/
struct aaline_fragment_shader *fs;
/*
* Driver interface/override functions
*/
void * (*driver_create_fs_state)(struct pipe_context *,
const struct pipe_shader_state *);
void (*driver_bind_fs_state)(struct pipe_context *, void *);
void (*driver_delete_fs_state)(struct pipe_context *, void *);
};
/**
* Subclass of tgsi_transform_context, used for transforming the
* user's fragment shader to add the special AA instructions.
*/
struct aa_transform_context {
struct tgsi_transform_context base;
uint64_t tempsUsed; /**< bitmask */
int colorOutput; /**< which output is the primary color */
int maxInput, maxGeneric; /**< max input index found */
int numImm; /**< number of immediate regsters */
int colorTemp, aaTemp; /**< temp registers */
};
/**
* TGSI declaration transform callback.
* Look for a free input attrib, and two free temp regs.
*/
static void
aa_transform_decl(struct tgsi_transform_context *ctx,
struct tgsi_full_declaration *decl)
{
struct aa_transform_context *aactx = (struct aa_transform_context *)ctx;
if (decl->Declaration.File == TGSI_FILE_OUTPUT &&
decl->Semantic.Name == TGSI_SEMANTIC_COLOR &&
decl->Semantic.Index == 0) {
aactx->colorOutput = decl->Range.First;
}
else if (decl->Declaration.File == TGSI_FILE_INPUT) {
if ((int) decl->Range.Last > aactx->maxInput)
aactx->maxInput = decl->Range.Last;
if (decl->Semantic.Name == TGSI_SEMANTIC_GENERIC &&
(int) decl->Semantic.Index > aactx->maxGeneric) {
aactx->maxGeneric = decl->Semantic.Index;
}
}
else if (decl->Declaration.File == TGSI_FILE_TEMPORARY) {
unsigned i;
for (i = decl->Range.First;
i <= decl->Range.Last; i++) {
/*
* XXX this bitfield doesn't really cut it...
*/
aactx->tempsUsed |= UINT64_C(1) << i;
}
}
ctx->emit_declaration(ctx, decl);
}
/**
* TGSI immediate declaration transform callback.
*/
static void
aa_immediate(struct tgsi_transform_context *ctx,
struct tgsi_full_immediate *imm)
{
struct aa_transform_context *aactx = (struct aa_transform_context *)ctx;
ctx->emit_immediate(ctx, imm);
aactx->numImm++;
}
/**
* Find the lowest zero bit, or -1 if bitfield is all ones.
*/
static int
free_bit(uint64_t bitfield)
{
return ffsll(~bitfield) - 1;
}
/**
* TGSI transform prolog callback.
*/
static void
aa_transform_prolog(struct tgsi_transform_context *ctx)
{
struct aa_transform_context *aactx = (struct aa_transform_context *) ctx;
uint64_t usedTemps = aactx->tempsUsed;
/* find two free temp regs */
aactx->colorTemp = free_bit(usedTemps);
usedTemps |= UINT64_C(1) << aactx->colorTemp;
aactx->aaTemp = free_bit(usedTemps);
assert(aactx->colorTemp >= 0);
assert(aactx->aaTemp >= 0);
/* declare new generic input/texcoord */
tgsi_transform_input_decl(ctx, aactx->maxInput + 1,
TGSI_SEMANTIC_GENERIC, aactx->maxGeneric + 1,
TGSI_INTERPOLATE_LINEAR);
/* declare new temp regs */
tgsi_transform_temp_decl(ctx, aactx->aaTemp);
tgsi_transform_temp_decl(ctx, aactx->colorTemp);
/* declare new immediate reg */
tgsi_transform_immediate_decl(ctx, 2.0, -1.0, 0.0, 0.25);
}
/**
* TGSI transform epilog callback.
*/
static void
aa_transform_epilog(struct tgsi_transform_context *ctx)
{
struct aa_transform_context *aactx = (struct aa_transform_context *) ctx;
if (aactx->colorOutput != -1) {
struct tgsi_full_instruction inst;
/* insert distance-based coverage code for antialiasing. */
/* saturate(linewidth - fabs(interpx), linelength - fabs(interpz) */
inst = tgsi_default_full_instruction();
inst.Instruction.Saturate = true;
inst.Instruction.Opcode = TGSI_OPCODE_ADD;
inst.Instruction.NumDstRegs = 1;
tgsi_transform_dst_reg(&inst.Dst[0], TGSI_FILE_TEMPORARY,
aactx->aaTemp, TGSI_WRITEMASK_XZ);
inst.Instruction.NumSrcRegs = 2;
tgsi_transform_src_reg(&inst.Src[1], TGSI_FILE_INPUT, aactx->maxInput + 1,
TGSI_SWIZZLE_X, TGSI_SWIZZLE_X,
TGSI_SWIZZLE_Z, TGSI_SWIZZLE_Z);
tgsi_transform_src_reg(&inst.Src[0], TGSI_FILE_INPUT, aactx->maxInput + 1,
TGSI_SWIZZLE_Y, TGSI_SWIZZLE_Y,
TGSI_SWIZZLE_W, TGSI_SWIZZLE_W);
inst.Src[1].Register.Absolute = true;
inst.Src[1].Register.Negate = true;
ctx->emit_instruction(ctx, &inst);
/* linelength * 2 - 1 */
tgsi_transform_op3_swz_inst(ctx, TGSI_OPCODE_MAD,
TGSI_FILE_TEMPORARY, aactx->aaTemp,
TGSI_WRITEMASK_Y,
TGSI_FILE_INPUT, aactx->maxInput + 1,
TGSI_SWIZZLE_W, false,
TGSI_FILE_IMMEDIATE, aactx->numImm,
TGSI_SWIZZLE_X,
TGSI_FILE_IMMEDIATE, aactx->numImm,
TGSI_SWIZZLE_Y);
/* MIN height alpha */
tgsi_transform_op2_swz_inst(ctx, TGSI_OPCODE_MIN,
TGSI_FILE_TEMPORARY, aactx->aaTemp,
TGSI_WRITEMASK_Z,
TGSI_FILE_TEMPORARY, aactx->aaTemp,
TGSI_SWIZZLE_Z,
TGSI_FILE_TEMPORARY, aactx->aaTemp,
TGSI_SWIZZLE_Y, false);
/* MUL width / height alpha */
tgsi_transform_op2_swz_inst(ctx, TGSI_OPCODE_MUL,
TGSI_FILE_TEMPORARY, aactx->aaTemp,
TGSI_WRITEMASK_W,
TGSI_FILE_TEMPORARY, aactx->aaTemp,
TGSI_SWIZZLE_X,
TGSI_FILE_TEMPORARY, aactx->aaTemp,
TGSI_SWIZZLE_Z, false);
/* MOV rgb */
tgsi_transform_op1_inst(ctx, TGSI_OPCODE_MOV,
TGSI_FILE_OUTPUT, aactx->colorOutput,
TGSI_WRITEMASK_XYZ,
TGSI_FILE_TEMPORARY, aactx->colorTemp);
/* MUL alpha */
tgsi_transform_op2_inst(ctx, TGSI_OPCODE_MUL,
TGSI_FILE_OUTPUT, aactx->colorOutput,
TGSI_WRITEMASK_W,
TGSI_FILE_TEMPORARY, aactx->colorTemp,
TGSI_FILE_TEMPORARY, aactx->aaTemp, false);
}
}
/**
* TGSI instruction transform callback.
* Replace writes to result.color w/ a temp reg.
*/
static void
aa_transform_inst(struct tgsi_transform_context *ctx,
struct tgsi_full_instruction *inst)
{
struct aa_transform_context *aactx = (struct aa_transform_context *) ctx;
unsigned i;
/*
* Look for writes to result.color and replace with colorTemp reg.
*/
for (i = 0; i < inst->Instruction.NumDstRegs; i++) {
struct tgsi_full_dst_register *dst = &inst->Dst[i];
if (dst->Register.File == TGSI_FILE_OUTPUT &&
dst->Register.Index == aactx->colorOutput) {
dst->Register.File = TGSI_FILE_TEMPORARY;
dst->Register.Index = aactx->colorTemp;
}
}
ctx->emit_instruction(ctx, inst);
}
/**
* Generate the frag shader we'll use for drawing AA lines.
* This will be the user's shader plus some arithmetic instructions.
*/
static bool
generate_aaline_fs(struct aaline_stage *aaline)
{
struct pipe_context *pipe = aaline->stage.draw->pipe;
const struct pipe_shader_state *orig_fs = &aaline->fs->state;
struct pipe_shader_state aaline_fs;
struct aa_transform_context transform;
const unsigned newLen = tgsi_num_tokens(orig_fs->tokens) + NUM_NEW_TOKENS;
aaline_fs = *orig_fs; /* copy to init */
memset(&transform, 0, sizeof(transform));
transform.colorOutput = -1;
transform.maxInput = -1;
transform.maxGeneric = -1;
transform.colorTemp = -1;
transform.aaTemp = -1;
transform.base.prolog = aa_transform_prolog;
transform.base.epilog = aa_transform_epilog;
transform.base.transform_instruction = aa_transform_inst;
transform.base.transform_declaration = aa_transform_decl;
transform.base.transform_immediate = aa_immediate;
aaline_fs.tokens = tgsi_transform_shader(orig_fs->tokens, newLen, &transform.base);
if (!aaline_fs.tokens)
return false;
#if 0 /* debug */
debug_printf("draw_aaline, orig shader:\n");
tgsi_dump(orig_fs->tokens, 0);
debug_printf("draw_aaline, new shader:\n");
tgsi_dump(aaline_fs.tokens, 0);
#endif
aaline->fs->aaline_fs = aaline->driver_create_fs_state(pipe, &aaline_fs);
if (aaline->fs->aaline_fs != NULL)
aaline->fs->generic_attrib = transform.maxGeneric + 1;
FREE((void *)aaline_fs.tokens);
return aaline->fs->aaline_fs != NULL;
}
static bool
generate_aaline_fs_nir(struct aaline_stage *aaline)
{
struct pipe_context *pipe = aaline->stage.draw->pipe;
const struct pipe_shader_state *orig_fs = &aaline->fs->state;
struct pipe_shader_state aaline_fs;
aaline_fs = *orig_fs; /* copy to init */
aaline_fs.ir.nir = nir_shader_clone(NULL, orig_fs->ir.nir);
if (!aaline_fs.ir.nir)
return false;
nir_lower_aaline_fs(aaline_fs.ir.nir, &aaline->fs->generic_attrib, NULL, NULL);
aaline->fs->aaline_fs = aaline->driver_create_fs_state(pipe, &aaline_fs);
if (aaline->fs->aaline_fs == NULL)
return false;
return true;
}
/**
* When we're about to draw our first AA line in a batch, this function is
* called to tell the driver to bind our modified fragment shader.
*/
static bool
bind_aaline_fragment_shader(struct aaline_stage *aaline)
{
struct draw_context *draw = aaline->stage.draw;
struct pipe_context *pipe = draw->pipe;
if (!aaline->fs->aaline_fs) {
if (aaline->fs->state.type == PIPE_SHADER_IR_NIR) {
if (!generate_aaline_fs_nir(aaline))
return false;
} else
if (!generate_aaline_fs(aaline))
return false;
}
draw->suspend_flushing = true;
aaline->driver_bind_fs_state(pipe, aaline->fs->aaline_fs);
draw->suspend_flushing = false;
return true;
}
static inline struct aaline_stage *
aaline_stage(struct draw_stage *stage)
{
return (struct aaline_stage *) stage;
}
/**
* Draw a wide line by drawing a quad, using geometry which will
* fullfill GL's antialiased line requirements.
*/
static void
aaline_line(struct draw_stage *stage, struct prim_header *header)
{
const struct aaline_stage *aaline = aaline_stage(stage);
const float half_width = aaline->half_line_width;
struct prim_header tri;
struct vertex_header *v[8];
unsigned coordPos = aaline->coord_slot;
unsigned posPos = aaline->pos_slot;
float *pos, *tex;
float dx = header->v[1]->data[posPos][0] - header->v[0]->data[posPos][0];
float dy = header->v[1]->data[posPos][1] - header->v[0]->data[posPos][1];
float length = sqrtf(dx * dx + dy * dy);
float c_a = dx / length, s_a = dy / length;
float half_length = 0.5 * length;
float t_l, t_w;
unsigned i;
half_length = half_length + 0.5f;
t_w = half_width;
t_l = 0.5f;
/* allocate/dup new verts */
for (i = 0; i < 4; i++) {
v[i] = dup_vert(stage, header->v[i/2], i);
}
/*
* Quad strip for line from v0 to v1 (*=endpoints):
*
* 1 3
* +-----------------------------+
* | |
* | *v0 v1* |
* | |
* +-----------------------------+
* 0 2
*/
/*
* We increase line length by 0.5 pixels (at each endpoint),
* and calculate the tri endpoints by moving them half-width
* distance away perpendicular to the line.
* XXX: since we change line endpoints (by 0.5 pixel), should
* actually re-interpolate all other values?
*/
/* new verts */
pos = v[0]->data[posPos];
pos[0] += (-t_l * c_a - t_w * s_a);
pos[1] += (-t_l * s_a + t_w * c_a);
pos = v[1]->data[posPos];
pos[0] += (-t_l * c_a - -t_w * s_a);
pos[1] += (-t_l * s_a + -t_w * c_a);
pos = v[2]->data[posPos];
pos[0] += (t_l * c_a - t_w * s_a);
pos[1] += (t_l * s_a + t_w * c_a);
pos = v[3]->data[posPos];
pos[0] += (t_l * c_a - -t_w * s_a);
pos[1] += (t_l * s_a + -t_w * c_a);
/* new texcoords */
tex = v[0]->data[coordPos];
ASSIGN_4V(tex, -half_width, half_width, -half_length, half_length);
tex = v[1]->data[coordPos];
ASSIGN_4V(tex, half_width, half_width, -half_length, half_length);
tex = v[2]->data[coordPos];
ASSIGN_4V(tex, -half_width, half_width, half_length, half_length);
tex = v[3]->data[coordPos];
ASSIGN_4V(tex, half_width, half_width, half_length, half_length);
tri.v[0] = v[2]; tri.v[1] = v[1]; tri.v[2] = v[0];
stage->next->tri(stage->next, &tri);
tri.v[0] = v[3]; tri.v[1] = v[1]; tri.v[2] = v[2];
stage->next->tri(stage->next, &tri);
}
static void
aaline_first_line(struct draw_stage *stage, struct prim_header *header)
{
auto struct aaline_stage *aaline = aaline_stage(stage);
struct draw_context *draw = stage->draw;
struct pipe_context *pipe = draw->pipe;
const struct pipe_rasterizer_state *rast = draw->rasterizer;
void *r;
assert(draw->rasterizer->line_smooth && !draw->rasterizer->multisample);
if (draw->rasterizer->line_width <= 1.0)
aaline->half_line_width = 1.0;
else
aaline->half_line_width = 0.5f * draw->rasterizer->line_width + 0.5f;
if (!draw->rasterizer->half_pixel_center)
/*
* The tex coords probably would need adjustments?
*/
debug_printf("aa lines without half pixel center may be wrong\n");
/*
* Bind (generate) our fragprog
*/
if (!bind_aaline_fragment_shader(aaline)) {
stage->line = draw_pipe_passthrough_line;
stage->line(stage, header);
return;
}
draw_aaline_prepare_outputs(draw, draw->pipeline.aaline);
draw->suspend_flushing = true;
/* Disable triangle culling, stippling, unfilled mode etc. */
r = draw_get_rasterizer_no_cull(draw, rast);
pipe->bind_rasterizer_state(pipe, r);
draw->suspend_flushing = false;
/* now really draw first line */
stage->line = aaline_line;
stage->line(stage, header);
}
static void
aaline_flush(struct draw_stage *stage, unsigned flags)
{
struct draw_context *draw = stage->draw;
struct aaline_stage *aaline = aaline_stage(stage);
struct pipe_context *pipe = draw->pipe;
stage->line = aaline_first_line;
stage->next->flush(stage->next, flags);
/* restore original frag shader */
draw->suspend_flushing = true;
aaline->driver_bind_fs_state(pipe, aaline->fs ? aaline->fs->driver_fs : NULL);
/* restore original rasterizer state */
if (draw->rast_handle) {
pipe->bind_rasterizer_state(pipe, draw->rast_handle);
}
draw->suspend_flushing = false;
draw_remove_extra_vertex_attribs(draw);
}
static void
aaline_reset_stipple_counter(struct draw_stage *stage)
{
stage->next->reset_stipple_counter(stage->next);
}
static void
aaline_destroy(struct draw_stage *stage)
{
struct aaline_stage *aaline = aaline_stage(stage);
struct pipe_context *pipe = stage->draw->pipe;
draw_free_temp_verts(stage);
/* restore the old entry points */
pipe->create_fs_state = aaline->driver_create_fs_state;
pipe->bind_fs_state = aaline->driver_bind_fs_state;
pipe->delete_fs_state = aaline->driver_delete_fs_state;
FREE(stage);
}
static struct aaline_stage *
draw_aaline_stage(struct draw_context *draw)
{
struct aaline_stage *aaline = CALLOC_STRUCT(aaline_stage);
if (!aaline)
return NULL;
aaline->stage.draw = draw;
aaline->stage.name = "aaline";
aaline->stage.next = NULL;
aaline->stage.point = draw_pipe_passthrough_point;
aaline->stage.line = aaline_first_line;
aaline->stage.tri = draw_pipe_passthrough_tri;
aaline->stage.flush = aaline_flush;
aaline->stage.reset_stipple_counter = aaline_reset_stipple_counter;
aaline->stage.destroy = aaline_destroy;
if (!draw_alloc_temp_verts(&aaline->stage, 8)) {
aaline->stage.destroy(&aaline->stage);
return NULL;
}
return aaline;
}
static struct aaline_stage *
aaline_stage_from_pipe(struct pipe_context *pipe)
{
struct draw_context *draw = (struct draw_context *) pipe->draw;
if (draw) {
return aaline_stage(draw->pipeline.aaline);
} else {
return NULL;
}
}
/**
* This function overrides the driver's create_fs_state() function and
* will typically be called by the gallium frontend.
*/
static void *
aaline_create_fs_state(struct pipe_context *pipe,
const struct pipe_shader_state *fs)
{
struct aaline_stage *aaline = aaline_stage_from_pipe(pipe);
struct aaline_fragment_shader *aafs = NULL;
if (!aaline)
return NULL;
aafs = CALLOC_STRUCT(aaline_fragment_shader);
if (!aafs)
return NULL;
aafs->state.type = fs->type;
if (fs->type == PIPE_SHADER_IR_TGSI)
aafs->state.tokens = tgsi_dup_tokens(fs->tokens);
else
aafs->state.ir.nir = nir_shader_clone(NULL, fs->ir.nir);
/* pass-through */
aafs->driver_fs = aaline->driver_create_fs_state(pipe, fs);
return aafs;
}
static void
aaline_bind_fs_state(struct pipe_context *pipe, void *fs)
{
struct aaline_stage *aaline = aaline_stage_from_pipe(pipe);
struct aaline_fragment_shader *aafs = (struct aaline_fragment_shader *) fs;
if (!aaline) {
return;
}
/* save current */
aaline->fs = aafs;
/* pass-through */
aaline->driver_bind_fs_state(pipe, (aafs ? aafs->driver_fs : NULL));
}
static void
aaline_delete_fs_state(struct pipe_context *pipe, void *fs)
{
struct aaline_stage *aaline = aaline_stage_from_pipe(pipe);
struct aaline_fragment_shader *aafs = (struct aaline_fragment_shader *) fs;
if (!aafs) {
return;
}
if (aaline) {
/* pass-through */
aaline->driver_delete_fs_state(pipe, aafs->driver_fs);
if (aafs->aaline_fs)
aaline->driver_delete_fs_state(pipe, aafs->aaline_fs);
}
if (aafs->state.type == PIPE_SHADER_IR_TGSI)
FREE((void*)aafs->state.tokens);
else
ralloc_free(aafs->state.ir.nir);
FREE(aafs);
}
void
draw_aaline_prepare_outputs(struct draw_context *draw,
struct draw_stage *stage)
{
struct aaline_stage *aaline = aaline_stage(stage);
const struct pipe_rasterizer_state *rast = draw->rasterizer;
/* update vertex attrib info */
aaline->pos_slot = draw_current_shader_position_output(draw);
if (!rast->line_smooth || rast->multisample)
return;
/* allocate the extra post-transformed vertex attribute */
if (aaline->fs && aaline->fs->aaline_fs)
aaline->coord_slot = draw_alloc_extra_vertex_attrib(draw,
TGSI_SEMANTIC_GENERIC,
aaline->fs->generic_attrib);
else
aaline->coord_slot = -1;
}
/**
* Called by drivers that want to install this AA line prim stage
* into the draw module's pipeline. This will not be used if the
* hardware has native support for AA lines.
*/
bool
draw_install_aaline_stage(struct draw_context *draw, struct pipe_context *pipe)
{
struct aaline_stage *aaline;
pipe->draw = (void *) draw;
/*
* Create / install AA line drawing / prim stage
*/
aaline = draw_aaline_stage(draw);
if (!aaline)
return false;
/* save original driver functions */
aaline->driver_create_fs_state = pipe->create_fs_state;
aaline->driver_bind_fs_state = pipe->bind_fs_state;
aaline->driver_delete_fs_state = pipe->delete_fs_state;
/* override the driver's functions */
pipe->create_fs_state = aaline_create_fs_state;
pipe->bind_fs_state = aaline_bind_fs_state;
pipe->delete_fs_state = aaline_delete_fs_state;
/* Install once everything is known to be OK:
*/
draw->pipeline.aaline = &aaline->stage;
return true;
}
@@ -0,0 +1,827 @@
/**************************************************************************
*
* Copyright 2008 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 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 ITS 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.
*
**************************************************************************/
/**
* AA point stage: AA points are converted to quads and rendered with a
* special fragment shader. Another approach would be to use a texture
* map image of a point, but experiments indicate the quality isn't nearly
* as good as this approach.
*
* Note: this looks a lot like draw_aaline.c but there's actually little
* if any code that can be shared.
*
* Authors: Brian Paul
*/
#include "pipe/p_context.h"
#include "pipe/p_defines.h"
#include "pipe/p_shader_tokens.h"
#include "tgsi/tgsi_transform.h"
#include "tgsi/tgsi_dump.h"
#include "util/u_math.h"
#include "util/u_memory.h"
#include "draw_context.h"
#include "draw_vs.h"
#include "draw_pipe.h"
#include "nir.h"
#include "nir/nir_draw_helpers.h"
/** Approx number of new tokens for instructions in aa_transform_inst() */
#define NUM_NEW_TOKENS 200
/*
* Enabling NORMALIZE might give _slightly_ better results.
* Basically, it controls whether we compute distance as d=sqrt(x*x+y*y) or
* d=x*x+y*y. Since we're working with a unit circle, the later seems
* close enough and saves some costly instructions.
*/
#define NORMALIZE 0
/**
* Subclass of pipe_shader_state to carry extra fragment shader info.
*/
struct aapoint_fragment_shader
{
struct pipe_shader_state state;
void *driver_fs; /**< the regular shader */
void *aapoint_fs; /**< the aa point-augmented shader */
int generic_attrib; /**< The generic input attrib/texcoord we'll use */
};
/**
* Subclass of draw_stage
*/
struct aapoint_stage
{
struct draw_stage stage;
/** half of pipe_rasterizer_state::point_size */
float radius;
/** vertex attrib slot containing point size */
int psize_slot;
/** this is the vertex attrib slot for the new texcoords */
unsigned tex_slot;
/** vertex attrib slot containing position */
unsigned pos_slot;
/** Type of Boolean variables on this hardware. */
nir_alu_type bool_type;
/** Currently bound fragment shader */
struct aapoint_fragment_shader *fs;
/*
* Driver interface/override functions
*/
void * (*driver_create_fs_state)(struct pipe_context *,
const struct pipe_shader_state *);
void (*driver_bind_fs_state)(struct pipe_context *, void *);
void (*driver_delete_fs_state)(struct pipe_context *, void *);
};
/**
* Subclass of tgsi_transform_context, used for transforming the
* user's fragment shader to add the special AA instructions.
*/
struct aa_transform_context {
struct tgsi_transform_context base;
uint32_t tempsUsed; /**< bitmask */
int colorOutput; /**< which output is the primary color */
int maxInput, maxGeneric; /**< max input index found */
int tmp0, colorTemp; /**< temp registers */
};
/**
* TGSI declaration transform callback.
* Look for two free temp regs and available input reg for new texcoords.
*/
static void
aa_transform_decl(struct tgsi_transform_context *ctx,
struct tgsi_full_declaration *decl)
{
struct aa_transform_context *aactx = (struct aa_transform_context *) ctx;
if (decl->Declaration.File == TGSI_FILE_OUTPUT &&
decl->Semantic.Name == TGSI_SEMANTIC_COLOR &&
decl->Semantic.Index == 0) {
aactx->colorOutput = decl->Range.First;
}
else if (decl->Declaration.File == TGSI_FILE_INPUT) {
if ((int) decl->Range.Last > aactx->maxInput)
aactx->maxInput = decl->Range.Last;
if (decl->Semantic.Name == TGSI_SEMANTIC_GENERIC &&
(int) decl->Semantic.Index > aactx->maxGeneric) {
aactx->maxGeneric = decl->Semantic.Index;
}
}
else if (decl->Declaration.File == TGSI_FILE_TEMPORARY) {
unsigned i;
for (i = decl->Range.First;
i <= decl->Range.Last; i++) {
aactx->tempsUsed |= 1u << i;
}
}
ctx->emit_declaration(ctx, decl);
}
/**
* TGSI transform callback.
* Insert new declarations and instructions before first instruction.
*/
static void
aa_transform_prolog(struct tgsi_transform_context *ctx)
{
/* emit our new declarations before the first instruction */
struct aa_transform_context *aactx = (struct aa_transform_context *) ctx;
struct tgsi_full_instruction newInst;
const int texInput = aactx->maxInput + 1;
int tmp0;
unsigned i;
/* find two free temp regs */
for (i = 0; i < 32; i++) {
if ((aactx->tempsUsed & (1u << i)) == 0) {
/* found a free temp */
if (aactx->tmp0 < 0)
aactx->tmp0 = i;
else if (aactx->colorTemp < 0)
aactx->colorTemp = i;
else
break;
}
}
assert(aactx->colorTemp != aactx->tmp0);
tmp0 = aactx->tmp0;
/* declare new generic input/texcoord */
tgsi_transform_input_decl(ctx, texInput,
TGSI_SEMANTIC_GENERIC, aactx->maxGeneric + 1,
TGSI_INTERPOLATE_LINEAR);
/* declare new temp regs */
tgsi_transform_temp_decl(ctx, tmp0);
tgsi_transform_temp_decl(ctx, aactx->colorTemp);
/*
* Emit code to compute fragment coverage, kill if outside point radius
*
* Temp reg0 usage:
* t0.x = distance of fragment from center point
* t0.y = boolean, is t0.x > 1.0, also misc temp usage
* t0.z = temporary for computing 1/(1-k) value
* t0.w = final coverage value
*/
/* MUL t0.xy, tex, tex; # compute x^2, y^2 */
tgsi_transform_op2_inst(ctx, TGSI_OPCODE_MUL,
TGSI_FILE_TEMPORARY, tmp0, TGSI_WRITEMASK_XY,
TGSI_FILE_INPUT, texInput,
TGSI_FILE_INPUT, texInput, false);
/* ADD t0.x, t0.x, t0.y; # x^2 + y^2 */
tgsi_transform_op2_swz_inst(ctx, TGSI_OPCODE_ADD,
TGSI_FILE_TEMPORARY, tmp0, TGSI_WRITEMASK_X,
TGSI_FILE_TEMPORARY, tmp0, TGSI_SWIZZLE_X,
TGSI_FILE_TEMPORARY, tmp0, TGSI_SWIZZLE_Y, false);
#if NORMALIZE /* OPTIONAL normalization of length */
/* RSQ t0.x, t0.x; */
tgsi_transform_op1_inst(ctx, TGSI_OPCODE_RSQ,
TGSI_FILE_TEMPORARY, tmp0, TGSI_WRITEMASK_X,
TGSI_FILE_TEMPORARY, tmp0);
/* RCP t0.x, t0.x; */
tgsi_transform_op1_inst(ctx, TGSI_OPCODE_RCP,
TGSI_FILE_TEMPORARY, tmp0, TGSI_WRITEMASK_X,
TGSI_FILE_TEMPORARY, tmp0);
#endif
/* SGT t0.y, t0.xxxx, tex.wwww; # bool b = d > 1 (NOTE tex.w == 1) */
tgsi_transform_op2_swz_inst(ctx, TGSI_OPCODE_SGT,
TGSI_FILE_TEMPORARY, tmp0, TGSI_WRITEMASK_Y,
TGSI_FILE_TEMPORARY, tmp0, TGSI_SWIZZLE_X,
TGSI_FILE_INPUT, texInput, TGSI_SWIZZLE_W, false);
/* KILL_IF -tmp0.yyyy; # if -tmp0.y < 0, KILL */
tgsi_transform_kill_inst(ctx, TGSI_FILE_TEMPORARY, tmp0,
TGSI_SWIZZLE_Y, true);
/* compute coverage factor = (1-d)/(1-k) */
/* SUB t0.z, tex.w, tex.z; # m = 1 - k */
tgsi_transform_op2_swz_inst(ctx, TGSI_OPCODE_ADD,
TGSI_FILE_TEMPORARY, tmp0, TGSI_WRITEMASK_Z,
TGSI_FILE_INPUT, texInput, TGSI_SWIZZLE_W,
TGSI_FILE_INPUT, texInput, TGSI_SWIZZLE_Z, true);
/* RCP t0.z, t0.z; # t0.z = 1 / m */
newInst = tgsi_default_full_instruction();
newInst.Instruction.Opcode = TGSI_OPCODE_RCP;
newInst.Instruction.NumDstRegs = 1;
newInst.Dst[0].Register.File = TGSI_FILE_TEMPORARY;
newInst.Dst[0].Register.Index = tmp0;
newInst.Dst[0].Register.WriteMask = TGSI_WRITEMASK_Z;
newInst.Instruction.NumSrcRegs = 1;
newInst.Src[0].Register.File = TGSI_FILE_TEMPORARY;
newInst.Src[0].Register.Index = tmp0;
newInst.Src[0].Register.SwizzleX = TGSI_SWIZZLE_Z;
ctx->emit_instruction(ctx, &newInst);
/* SUB t0.y, 1, t0.x; # d = 1 - d */
tgsi_transform_op2_swz_inst(ctx, TGSI_OPCODE_ADD,
TGSI_FILE_TEMPORARY, tmp0, TGSI_WRITEMASK_Y,
TGSI_FILE_INPUT, texInput, TGSI_SWIZZLE_W,
TGSI_FILE_TEMPORARY, tmp0, TGSI_SWIZZLE_X, true);
/* MUL t0.w, t0.y, t0.z; # coverage = d * m */
tgsi_transform_op2_swz_inst(ctx, TGSI_OPCODE_MUL,
TGSI_FILE_TEMPORARY, tmp0, TGSI_WRITEMASK_W,
TGSI_FILE_TEMPORARY, tmp0, TGSI_SWIZZLE_Y,
TGSI_FILE_TEMPORARY, tmp0, TGSI_SWIZZLE_Z, false);
/* SLE t0.y, t0.x, tex.z; # bool b = distance <= k */
tgsi_transform_op2_swz_inst(ctx, TGSI_OPCODE_SLE,
TGSI_FILE_TEMPORARY, tmp0, TGSI_WRITEMASK_Y,
TGSI_FILE_TEMPORARY, tmp0, TGSI_SWIZZLE_X,
TGSI_FILE_INPUT, texInput, TGSI_SWIZZLE_Z, false);
/* CMP t0.w, -t0.y, tex.w, t0.w;
* # if -t0.y < 0 then
* t0.w = 1
* else
* t0.w = t0.w
*/
tgsi_transform_op3_swz_inst(ctx, TGSI_OPCODE_CMP,
TGSI_FILE_TEMPORARY, tmp0, TGSI_WRITEMASK_W,
TGSI_FILE_TEMPORARY, tmp0, TGSI_SWIZZLE_Y, 1,
TGSI_FILE_INPUT, texInput, TGSI_SWIZZLE_W,
TGSI_FILE_TEMPORARY, tmp0, TGSI_SWIZZLE_W);
}
/**
* TGSI transform callback.
* Insert new instructions before the END instruction.
*/
static void
aa_transform_epilog(struct tgsi_transform_context *ctx)
{
struct aa_transform_context *aactx = (struct aa_transform_context *) ctx;
/* add alpha modulation code at tail of program */
/* MOV result.color.xyz, colorTemp; */
tgsi_transform_op1_inst(ctx, TGSI_OPCODE_MOV,
TGSI_FILE_OUTPUT, aactx->colorOutput,
TGSI_WRITEMASK_XYZ,
TGSI_FILE_TEMPORARY, aactx->colorTemp);
/* MUL result.color.w, colorTemp, tmp0.w; */
tgsi_transform_op2_inst(ctx, TGSI_OPCODE_MUL,
TGSI_FILE_OUTPUT, aactx->colorOutput,
TGSI_WRITEMASK_W,
TGSI_FILE_TEMPORARY, aactx->colorTemp,
TGSI_FILE_TEMPORARY, aactx->tmp0, false);
}
/**
* TGSI transform callback.
* Called per instruction.
* Replace writes to result.color w/ a temp reg.
*/
static void
aa_transform_inst(struct tgsi_transform_context *ctx,
struct tgsi_full_instruction *inst)
{
struct aa_transform_context *aactx = (struct aa_transform_context *) ctx;
unsigned i;
/* Not an END instruction.
* Look for writes to result.color and replace with colorTemp reg.
*/
for (i = 0; i < inst->Instruction.NumDstRegs; i++) {
struct tgsi_full_dst_register *dst = &inst->Dst[i];
if (dst->Register.File == TGSI_FILE_OUTPUT &&
dst->Register.Index == aactx->colorOutput) {
dst->Register.File = TGSI_FILE_TEMPORARY;
dst->Register.Index = aactx->colorTemp;
}
}
ctx->emit_instruction(ctx, inst);
}
/**
* Generate the frag shader we'll use for drawing AA points.
* This will be the user's shader plus some texture/modulate instructions.
*/
static bool
generate_aapoint_fs(struct aapoint_stage *aapoint)
{
const struct pipe_shader_state *orig_fs = &aapoint->fs->state;
struct pipe_shader_state aapoint_fs;
struct aa_transform_context transform;
const unsigned newLen = tgsi_num_tokens(orig_fs->tokens) + NUM_NEW_TOKENS;
struct pipe_context *pipe = aapoint->stage.draw->pipe;
aapoint_fs = *orig_fs; /* copy to init */
assert(aapoint_fs.type == PIPE_SHADER_IR_TGSI);
memset(&transform, 0, sizeof(transform));
transform.colorOutput = -1;
transform.maxInput = -1;
transform.maxGeneric = -1;
transform.colorTemp = -1;
transform.tmp0 = -1;
transform.base.prolog = aa_transform_prolog;
transform.base.epilog = aa_transform_epilog;
transform.base.transform_instruction = aa_transform_inst;
transform.base.transform_declaration = aa_transform_decl;
aapoint_fs.tokens = tgsi_transform_shader(orig_fs->tokens, newLen, &transform.base);
if (!aapoint_fs.tokens)
return false;
#if 0 /* debug */
debug_printf("draw_aapoint, orig shader:\n");
tgsi_dump(orig_fs->tokens, 0);
debug_printf("draw_aapoint, new shader:\n");
tgsi_dump(aapoint_fs.tokens, 0);
#endif
aapoint->fs->aapoint_fs
= aapoint->driver_create_fs_state(pipe, &aapoint_fs);
if (aapoint->fs->aapoint_fs == NULL)
goto fail;
aapoint->fs->generic_attrib = transform.maxGeneric + 1;
FREE((void *)aapoint_fs.tokens);
return true;
fail:
FREE((void *)aapoint_fs.tokens);
return false;
}
static bool
generate_aapoint_fs_nir(struct aapoint_stage *aapoint)
{
struct pipe_context *pipe = aapoint->stage.draw->pipe;
const struct pipe_shader_state *orig_fs = &aapoint->fs->state;
struct pipe_shader_state aapoint_fs;
aapoint_fs = *orig_fs; /* copy to init */
aapoint_fs.ir.nir = nir_shader_clone(NULL, orig_fs->ir.nir);
if (!aapoint_fs.ir.nir)
return false;
nir_lower_aapoint_fs(aapoint_fs.ir.nir, &aapoint->fs->generic_attrib, aapoint->bool_type);
aapoint->fs->aapoint_fs = aapoint->driver_create_fs_state(pipe, &aapoint_fs);
if (aapoint->fs->aapoint_fs == NULL)
goto fail;
return true;
fail:
return false;
}
/**
* When we're about to draw our first AA point in a batch, this function is
* called to tell the driver to bind our modified fragment shader.
*/
static bool
bind_aapoint_fragment_shader(struct aapoint_stage *aapoint)
{
struct draw_context *draw = aapoint->stage.draw;
struct pipe_context *pipe = draw->pipe;
if (!aapoint->fs->aapoint_fs) {
if (aapoint->fs->state.type == PIPE_SHADER_IR_NIR) {
if (!generate_aapoint_fs_nir(aapoint))
return false;
} else if (!generate_aapoint_fs(aapoint))
return false;
}
draw->suspend_flushing = true;
aapoint->driver_bind_fs_state(pipe, aapoint->fs->aapoint_fs);
draw->suspend_flushing = false;
return true;
}
static inline struct aapoint_stage *
aapoint_stage(struct draw_stage *stage)
{
return (struct aapoint_stage *) stage;
}
/**
* Draw an AA point by drawing a quad.
*/
static void
aapoint_point(struct draw_stage *stage, struct prim_header *header)
{
const struct aapoint_stage *aapoint = aapoint_stage(stage);
struct prim_header tri;
struct vertex_header *v[4];
const unsigned tex_slot = aapoint->tex_slot;
const unsigned pos_slot = aapoint->pos_slot;
float radius, *pos, *tex;
float k;
if (aapoint->psize_slot >= 0) {
radius = 0.5f * header->v[0]->data[aapoint->psize_slot][0];
}
else {
radius = aapoint->radius;
}
/*
* Note: the texcoords (generic attrib, really) we use are special:
* The S and T components simply vary from -1 to +1.
* The R component is k, below.
* The Q component is 1.0 and will used as a handy constant in the
* fragment shader.
*/
/*
* k is the threshold distance from the point's center at which
* we begin alpha attenuation (the coverage value).
* Operating within a unit circle, we'll compute the fragment's
* distance 'd' from the center point using the texcoords.
* IF d > 1.0 THEN
* KILL fragment
* ELSE IF d > k THEN
* compute coverage in [0,1] proportional to d in [k, 1].
* ELSE
* coverage = 1.0; // full coverage
* ENDIF
*
* Note: the ELSEIF and ELSE clauses are actually implemented with CMP to
* avoid using IF/ELSE/ENDIF TGSI opcodes.
*/
#if !NORMALIZE
k = 1.0f / radius;
k = 1.0f - 2.0f * k + k * k;
#else
k = 1.0f - 1.0f / radius;
#endif
/* allocate/dup new verts */
for (unsigned i = 0; i < 4; i++) {
v[i] = dup_vert(stage, header->v[0], i);
}
/* new verts */
pos = v[0]->data[pos_slot];
pos[0] -= radius;
pos[1] -= radius;
pos = v[1]->data[pos_slot];
pos[0] += radius;
pos[1] -= radius;
pos = v[2]->data[pos_slot];
pos[0] += radius;
pos[1] += radius;
pos = v[3]->data[pos_slot];
pos[0] -= radius;
pos[1] += radius;
/* new texcoords */
tex = v[0]->data[tex_slot];
ASSIGN_4V(tex, -1, -1, k, 1);
tex = v[1]->data[tex_slot];
ASSIGN_4V(tex, 1, -1, k, 1);
tex = v[2]->data[tex_slot];
ASSIGN_4V(tex, 1, 1, k, 1);
tex = v[3]->data[tex_slot];
ASSIGN_4V(tex, -1, 1, k, 1);
/* emit 2 tris for the quad strip */
tri.v[0] = v[0];
tri.v[1] = v[1];
tri.v[2] = v[2];
stage->next->tri(stage->next, &tri);
tri.v[0] = v[0];
tri.v[1] = v[2];
tri.v[2] = v[3];
stage->next->tri(stage->next, &tri);
}
static void
aapoint_first_point(struct draw_stage *stage, struct prim_header *header)
{
auto struct aapoint_stage *aapoint = aapoint_stage(stage);
struct draw_context *draw = stage->draw;
struct pipe_context *pipe = draw->pipe;
const struct pipe_rasterizer_state *rast = draw->rasterizer;
void *r;
assert(draw->rasterizer->point_smooth && !draw->rasterizer->multisample);
if (draw->rasterizer->point_size <= 2.0)
aapoint->radius = 1.0;
else
aapoint->radius = 0.5f * draw->rasterizer->point_size;
/*
* Bind (generate) our fragprog.
*/
bind_aapoint_fragment_shader(aapoint);
draw_aapoint_prepare_outputs(draw, draw->pipeline.aapoint);
draw->suspend_flushing = true;
/* Disable triangle culling, stippling, unfilled mode etc. */
r = draw_get_rasterizer_no_cull(draw, rast);
pipe->bind_rasterizer_state(pipe, r);
draw->suspend_flushing = false;
/* now really draw first point */
stage->point = aapoint_point;
stage->point(stage, header);
}
static void
aapoint_flush(struct draw_stage *stage, unsigned flags)
{
struct draw_context *draw = stage->draw;
struct aapoint_stage *aapoint = aapoint_stage(stage);
struct pipe_context *pipe = draw->pipe;
stage->point = aapoint_first_point;
stage->next->flush(stage->next, flags);
/* restore original frag shader */
draw->suspend_flushing = true;
aapoint->driver_bind_fs_state(pipe, aapoint->fs ? aapoint->fs->driver_fs : NULL);
/* restore original rasterizer state */
if (draw->rast_handle) {
pipe->bind_rasterizer_state(pipe, draw->rast_handle);
}
draw->suspend_flushing = false;
draw_remove_extra_vertex_attribs(draw);
}
static void
aapoint_reset_stipple_counter(struct draw_stage *stage)
{
stage->next->reset_stipple_counter(stage->next);
}
static void
aapoint_destroy(struct draw_stage *stage)
{
struct aapoint_stage* aapoint = aapoint_stage(stage);
struct pipe_context *pipe = stage->draw->pipe;
draw_free_temp_verts(stage);
/* restore the old entry points */
pipe->create_fs_state = aapoint->driver_create_fs_state;
pipe->bind_fs_state = aapoint->driver_bind_fs_state;
pipe->delete_fs_state = aapoint->driver_delete_fs_state;
FREE(stage);
}
void
draw_aapoint_prepare_outputs(struct draw_context *draw,
struct draw_stage *stage)
{
struct aapoint_stage *aapoint = aapoint_stage(stage);
const struct pipe_rasterizer_state *rast = draw->rasterizer;
/* update vertex attrib info */
aapoint->pos_slot = draw_current_shader_position_output(draw);
if (!rast->point_smooth || rast->multisample)
return;
if (aapoint->fs && aapoint->fs->aapoint_fs) {
/* allocate the extra post-transformed vertex attribute */
aapoint->tex_slot = draw_alloc_extra_vertex_attrib(draw,
TGSI_SEMANTIC_GENERIC,
aapoint->fs->generic_attrib);
assert(aapoint->tex_slot > 0); /* output[0] is vertex pos */
} else {
aapoint->tex_slot = -1;
}
/* find psize slot in post-transform vertex */
aapoint->psize_slot = -1;
if (draw->rasterizer->point_size_per_vertex) {
const struct tgsi_shader_info *info = draw_get_shader_info(draw);
/* find PSIZ vertex output */
for (unsigned i = 0; i < info->num_outputs; i++) {
if (info->output_semantic_name[i] == TGSI_SEMANTIC_PSIZE) {
aapoint->psize_slot = i;
break;
}
}
}
}
static struct aapoint_stage *
draw_aapoint_stage(struct draw_context *draw, nir_alu_type bool_type)
{
struct aapoint_stage *aapoint = CALLOC_STRUCT(aapoint_stage);
if (!aapoint)
goto fail;
aapoint->stage.draw = draw;
aapoint->stage.name = "aapoint";
aapoint->stage.next = NULL;
aapoint->stage.point = aapoint_first_point;
aapoint->stage.line = draw_pipe_passthrough_line;
aapoint->stage.tri = draw_pipe_passthrough_tri;
aapoint->stage.flush = aapoint_flush;
aapoint->stage.reset_stipple_counter = aapoint_reset_stipple_counter;
aapoint->stage.destroy = aapoint_destroy;
aapoint->bool_type = bool_type;
if (!draw_alloc_temp_verts(&aapoint->stage, 4))
goto fail;
return aapoint;
fail:
if (aapoint)
aapoint->stage.destroy(&aapoint->stage);
return NULL;
}
static struct aapoint_stage *
aapoint_stage_from_pipe(struct pipe_context *pipe)
{
struct draw_context *draw = (struct draw_context *) pipe->draw;
return aapoint_stage(draw->pipeline.aapoint);
}
/**
* This function overrides the driver's create_fs_state() function and
* will typically be called by the gallium frontend.
*/
static void *
aapoint_create_fs_state(struct pipe_context *pipe,
const struct pipe_shader_state *fs)
{
struct aapoint_stage *aapoint = aapoint_stage_from_pipe(pipe);
struct aapoint_fragment_shader *aafs = CALLOC_STRUCT(aapoint_fragment_shader);
if (!aafs)
return NULL;
aafs->state.type = fs->type;
if (fs->type == PIPE_SHADER_IR_TGSI)
aafs->state.tokens = tgsi_dup_tokens(fs->tokens);
else
aafs->state.ir.nir = nir_shader_clone(NULL, fs->ir.nir);
/* pass-through */
aafs->driver_fs = aapoint->driver_create_fs_state(pipe, fs);
return aafs;
}
static void
aapoint_bind_fs_state(struct pipe_context *pipe, void *fs)
{
struct aapoint_stage *aapoint = aapoint_stage_from_pipe(pipe);
struct aapoint_fragment_shader *aafs = (struct aapoint_fragment_shader *) fs;
/* save current */
aapoint->fs = aafs;
/* pass-through */
aapoint->driver_bind_fs_state(pipe,
(aafs ? aafs->driver_fs : NULL));
}
static void
aapoint_delete_fs_state(struct pipe_context *pipe, void *fs)
{
struct aapoint_stage *aapoint = aapoint_stage_from_pipe(pipe);
struct aapoint_fragment_shader *aafs = (struct aapoint_fragment_shader *) fs;
/* pass-through */
aapoint->driver_delete_fs_state(pipe, aafs->driver_fs);
if (aafs->aapoint_fs)
aapoint->driver_delete_fs_state(pipe, aafs->aapoint_fs);
if (aafs->state.type == PIPE_SHADER_IR_TGSI)
FREE((void*)aafs->state.tokens);
else
ralloc_free(aafs->state.ir.nir);
FREE(aafs);
}
/**
* Called by drivers that want to install this AA point prim stage
* into the draw module's pipeline. This will not be used if the
* hardware has native support for AA points.
*/
bool
draw_install_aapoint_stage(struct draw_context *draw,
struct pipe_context *pipe,
nir_alu_type bool_type)
{
struct aapoint_stage *aapoint;
pipe->draw = (void *) draw;
/*
* Create / install AA point drawing / prim stage
*/
aapoint = draw_aapoint_stage(draw, bool_type);
if (!aapoint)
return false;
/* save original driver functions */
aapoint->driver_create_fs_state = pipe->create_fs_state;
aapoint->driver_bind_fs_state = pipe->bind_fs_state;
aapoint->driver_delete_fs_state = pipe->delete_fs_state;
/* override the driver's functions */
pipe->create_fs_state = aapoint_create_fs_state;
pipe->bind_fs_state = aapoint_bind_fs_state;
pipe->delete_fs_state = aapoint_delete_fs_state;
draw->pipeline.aapoint = &aapoint->stage;
return true;
}
+1000
View File
@@ -0,0 +1,1000 @@
/**************************************************************************
*
* Copyright 2007 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 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 ITS 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.
*
**************************************************************************/
/**
* \brief Clipping stage
*
* \author Keith Whitwell <[email protected]>
*/
#include "util/u_bitcast.h"
#include "util/u_memory.h"
#include "util/u_math.h"
#include "pipe/p_shader_tokens.h"
#include "draw_vs.h"
#include "draw_pipe.h"
#include "draw_fs.h"
#include "draw_gs.h"
/** Set to 1 to enable printing of coords before/after clipping */
#define DEBUG_CLIP 0
#define MAX_CLIPPED_VERTICES ((2 * (6 + PIPE_MAX_CLIP_PLANES))+1)
struct clip_stage {
struct draw_stage stage; /**< base class */
unsigned pos_attr;
bool have_clipdist;
int cv_attr;
/* List of the attributes to be constant interpolated. */
unsigned num_const_attribs;
uint8_t const_attribs[PIPE_MAX_SHADER_OUTPUTS];
/* List of the attributes to be linear interpolated. */
unsigned num_linear_attribs;
uint8_t linear_attribs[PIPE_MAX_SHADER_OUTPUTS];
/* List of the attributes to be perspective interpolated. */
unsigned num_perspect_attribs;
uint8_t perspect_attribs[PIPE_MAX_SHADER_OUTPUTS];
float (*plane)[4];
};
/** Cast wrapper */
static inline struct clip_stage *
clip_stage(struct draw_stage *stage)
{
return (struct clip_stage *) stage;
}
static inline unsigned
draw_viewport_index(struct draw_context *draw,
const struct vertex_header *leading_vertex)
{
if (draw_current_shader_uses_viewport_index(draw)) {
unsigned viewport_index_output =
draw_current_shader_viewport_index_output(draw);
unsigned viewport_index =
u_bitcast_f2u(leading_vertex->data[viewport_index_output][0]);
return draw_clamp_viewport_idx(viewport_index);
} else {
return 0;
}
}
#define LINTERP(T, OUT, IN) ((OUT) + (T) * ((IN) - (OUT)))
/* All attributes are float[4], so this is easy:
*/
static void
interp_attr(float dst[4],
float t,
const float in[4],
const float out[4])
{
dst[0] = LINTERP(t, out[0], in[0]);
dst[1] = LINTERP(t, out[1], in[1]);
dst[2] = LINTERP(t, out[2], in[2]);
dst[3] = LINTERP(t, out[3], in[3]);
}
/**
* Copy flat shaded attributes src vertex to dst vertex.
*/
static void
copy_flat(struct draw_stage *stage,
struct vertex_header *dst,
const struct vertex_header *src)
{
const struct clip_stage *clipper = clip_stage(stage);
for (unsigned i = 0; i < clipper->num_const_attribs; i++) {
const unsigned attr = clipper->const_attribs[i];
COPY_4FV(dst->data[attr], src->data[attr]);
}
}
/* Interpolate between two vertices to produce a third.
*/
static void
interp(const struct clip_stage *clip,
struct vertex_header *dst,
float t,
const struct vertex_header *out,
const struct vertex_header *in,
unsigned viewport_index)
{
const unsigned pos_attr = clip->pos_attr;
/* Vertex header.
*/
dst->clipmask = 0;
dst->edgeflag = 0; /* will get overwritten later */
dst->pad = 0;
dst->vertex_id = UNDEFINED_VERTEX_ID;
/* Interpolate the clip-space coords.
*/
if (clip->cv_attr >= 0) {
interp_attr(dst->data[clip->cv_attr], t,
in->data[clip->cv_attr], out->data[clip->cv_attr]);
}
/* interpolate the clip-space position */
interp_attr(dst->clip_pos, t, in->clip_pos, out->clip_pos);
/* Do the projective divide and viewport transformation to get
* new window coordinates:
*/
{
const float *pos = dst->clip_pos;
const float *scale =
clip->stage.draw->viewports[viewport_index].scale;
const float *trans =
clip->stage.draw->viewports[viewport_index].translate;
const float oow = 1.0f / pos[3];
dst->data[pos_attr][0] = pos[0] * oow * scale[0] + trans[0];
dst->data[pos_attr][1] = pos[1] * oow * scale[1] + trans[1];
dst->data[pos_attr][2] = pos[2] * oow * scale[2] + trans[2];
dst->data[pos_attr][3] = oow;
}
/* interp perspective attribs */
for (unsigned j = 0; j < clip->num_perspect_attribs; j++) {
const unsigned attr = clip->perspect_attribs[j];
interp_attr(dst->data[attr], t, in->data[attr], out->data[attr]);
}
/**
* Compute the t in screen-space instead of 3d space to use
* for noperspective interpolation.
*
* The points can be aligned with the X axis, so in that case try
* the Y. When both points are at the same screen position, we can
* pick whatever value (the interpolated point won't be in front
* anyway), so just use the 3d t.
*/
if (clip->num_linear_attribs) {
float t_nopersp = t;
/* find either in.x != out.x or in.y != out.y */
for (int k = 0; k < 2; k++) {
if (in->clip_pos[k] != out->clip_pos[k]) {
/* do divide by W, then compute linear interpolation factor */
float in_coord = in->clip_pos[k] / in->clip_pos[3];
float out_coord = out->clip_pos[k] / out->clip_pos[3];
float dst_coord = dst->clip_pos[k] / dst->clip_pos[3];
t_nopersp = (dst_coord - out_coord) / (in_coord - out_coord);
break;
}
}
for (unsigned j = 0; j < clip->num_linear_attribs; j++) {
const unsigned attr = clip->linear_attribs[j];
interp_attr(dst->data[attr], t_nopersp, in->data[attr], out->data[attr]);
}
}
}
/**
* Emit a post-clip polygon to the next pipeline stage. The polygon
* will be convex and the provoking vertex will always be vertex[0].
*/
static void
emit_poly(struct draw_stage *stage,
struct vertex_header **inlist,
const bool *edgeflags,
unsigned n,
const struct prim_header *origPrim)
{
const struct clip_stage *clipper = clip_stage(stage);
uint16_t edge_first, edge_middle, edge_last;
if (stage->draw->rasterizer->flatshade_first) {
edge_first = DRAW_PIPE_EDGE_FLAG_0;
edge_middle = DRAW_PIPE_EDGE_FLAG_1;
edge_last = DRAW_PIPE_EDGE_FLAG_2;
} else {
edge_first = DRAW_PIPE_EDGE_FLAG_2;
edge_middle = DRAW_PIPE_EDGE_FLAG_0;
edge_last = DRAW_PIPE_EDGE_FLAG_1;
}
if (!edgeflags[0])
edge_first = 0;
/* later stages may need the determinant, but only the sign matters */
struct prim_header header;
header.det = origPrim->det;
header.flags = DRAW_PIPE_RESET_STIPPLE | edge_first | edge_middle;
header.pad = 0;
for (unsigned i = 2; i < n; i++, header.flags = edge_middle) {
/* order the triangle verts to respect the provoking vertex mode */
if (stage->draw->rasterizer->flatshade_first) {
header.v[0] = inlist[0]; /* the provoking vertex */
header.v[1] = inlist[i-1];
header.v[2] = inlist[i];
} else {
header.v[0] = inlist[i-1];
header.v[1] = inlist[i];
header.v[2] = inlist[0]; /* the provoking vertex */
}
if (!edgeflags[i-1]) {
header.flags &= ~edge_middle;
}
if (i == n - 1 && edgeflags[i])
header.flags |= edge_last;
if (DEBUG_CLIP) {
debug_printf("Clipped tri: (flat-shade-first = %d)\n",
stage->draw->rasterizer->flatshade_first);
for (unsigned j = 0; j < 3; j++) {
debug_printf(" Vert %d: clip pos: %f %f %f %f\n", j,
header.v[j]->clip_pos[0],
header.v[j]->clip_pos[1],
header.v[j]->clip_pos[2],
header.v[j]->clip_pos[3]);
if (clipper->cv_attr >= 0) {
debug_printf(" Vert %d: cv: %f %f %f %f\n", j,
header.v[j]->data[clipper->cv_attr][0],
header.v[j]->data[clipper->cv_attr][1],
header.v[j]->data[clipper->cv_attr][2],
header.v[j]->data[clipper->cv_attr][3]);
}
for (unsigned k = 0; k < draw_num_shader_outputs(stage->draw); k++) {
debug_printf(" Vert %d: Attr %d: %f %f %f %f\n", j, k,
header.v[j]->data[k][0],
header.v[j]->data[k][1],
header.v[j]->data[k][2],
header.v[j]->data[k][3]);
}
}
}
stage->next->tri(stage->next, &header);
}
}
static inline float
dot4(const float *a, const float *b)
{
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];
}
/*
* this function extracts the clip distance for the current plane,
* it first checks if the shader provided a clip distance, otherwise
* it works out the value using the clipvertex
*/
static inline float
getclipdist(const struct clip_stage *clipper,
struct vertex_header *vert,
int plane_idx)
{
const float *plane;
float dp;
if (plane_idx < 6) {
/* ordinary xyz view volume clipping uses pos output */
plane = clipper->plane[plane_idx];
dp = dot4(vert->clip_pos, plane);
}
else if (clipper->have_clipdist) {
/* pick the correct clipdistance element from the output vectors */
int _idx = plane_idx - 6;
int cdi = _idx >= 4;
int vidx = cdi ? _idx - 4 : _idx;
dp = vert->data[draw_current_shader_ccdistance_output(clipper->stage.draw, cdi)][vidx];
} else {
/*
* legacy user clip planes or gl_ClipVertex
*/
plane = clipper->plane[plane_idx];
if (clipper->cv_attr >= 0) {
dp = dot4(vert->data[clipper->cv_attr], plane);
}
else {
dp = dot4(vert->clip_pos, plane);
}
}
return dp;
}
/* Clip a triangle against the viewport and user clip planes.
*/
static void
do_clip_tri(struct draw_stage *stage,
struct prim_header *header,
unsigned clipmask)
{
struct clip_stage *clipper = clip_stage(stage);
struct vertex_header *a[MAX_CLIPPED_VERTICES];
struct vertex_header *b[MAX_CLIPPED_VERTICES];
struct vertex_header **inlist = a;
struct vertex_header **outlist = b;
struct vertex_header *prov_vertex;
unsigned tmpnr = 0;
unsigned n = 3;
bool aEdges[MAX_CLIPPED_VERTICES];
bool bEdges[MAX_CLIPPED_VERTICES];
bool *inEdges = aEdges;
bool *outEdges = bEdges;
int viewport_index = 0;
inlist[0] = header->v[0];
inlist[1] = header->v[1];
inlist[2] = header->v[2];
/*
* For d3d10, we need to take this from the leading (first) vertex.
* For GL, we could do anything (as long as we advertize
* GL_UNDEFINED_VERTEX for the VIEWPORT_INDEX_PROVOKING_VERTEX query),
* but it needs to be consistent with what other parts (i.e. driver)
* will do, and that seems easier with GL_PROVOKING_VERTEX logic.
*/
if (stage->draw->rasterizer->flatshade_first) {
prov_vertex = inlist[0];
} else {
prov_vertex = inlist[2];
}
viewport_index = draw_viewport_index(clipper->stage.draw, prov_vertex);
if (DEBUG_CLIP) {
const float *v0 = header->v[0]->clip_pos;
const float *v1 = header->v[1]->clip_pos;
const float *v2 = header->v[2]->clip_pos;
debug_printf("Clip triangle pos:\n");
debug_printf(" %f, %f, %f, %f\n", v0[0], v0[1], v0[2], v0[3]);
debug_printf(" %f, %f, %f, %f\n", v1[0], v1[1], v1[2], v1[3]);
debug_printf(" %f, %f, %f, %f\n", v2[0], v2[1], v2[2], v2[3]);
if (clipper->cv_attr >= 0) {
const float *v0 = header->v[0]->data[clipper->cv_attr];
const float *v1 = header->v[1]->data[clipper->cv_attr];
const float *v2 = header->v[2]->data[clipper->cv_attr];
debug_printf("Clip triangle cv:\n");
debug_printf(" %f, %f, %f, %f\n", v0[0], v0[1], v0[2], v0[3]);
debug_printf(" %f, %f, %f, %f\n", v1[0], v1[1], v1[2], v1[3]);
debug_printf(" %f, %f, %f, %f\n", v2[0], v2[1], v2[2], v2[3]);
}
}
/*
* Note: at this point we can't just use the per-vertex edge flags.
* We have to observe the edge flag bits set in header->flags which
* were set during primitive decomposition. Put those flags into
* an edge flags array which parallels the vertex array.
* Later, in the 'unfilled' pipeline stage we'll draw the edge if both
* the header.flags bit is set AND the per-vertex edgeflag field is set.
*/
inEdges[0] = !!(header->flags & DRAW_PIPE_EDGE_FLAG_0);
inEdges[1] = !!(header->flags & DRAW_PIPE_EDGE_FLAG_1);
inEdges[2] = !!(header->flags & DRAW_PIPE_EDGE_FLAG_2);
while (clipmask && n >= 3) {
const unsigned plane_idx = ffs(clipmask)-1;
const bool is_user_clip_plane = plane_idx >= 6;
struct vertex_header *vert_prev = inlist[0];
bool *edge_prev = &inEdges[0];
float dp_prev;
unsigned outcount = 0;
dp_prev = getclipdist(clipper, vert_prev, plane_idx);
clipmask &= ~(1<<plane_idx);
if (util_is_inf_or_nan(dp_prev))
return; //discard nan
assert(n < MAX_CLIPPED_VERTICES);
if (n >= MAX_CLIPPED_VERTICES)
return;
inlist[n] = inlist[0]; /* prevent rotation of vertices */
inEdges[n] = inEdges[0];
for (unsigned i = 1; i <= n; i++) {
struct vertex_header *vert = inlist[i];
bool *edge = &inEdges[i];
bool different_sign;
float dp = getclipdist(clipper, vert, plane_idx);
if (util_is_inf_or_nan(dp))
return; //discard nan
if (dp_prev >= 0.0f) {
assert(outcount < MAX_CLIPPED_VERTICES);
if (outcount >= MAX_CLIPPED_VERTICES)
return;
outEdges[outcount] = *edge_prev;
outlist[outcount++] = vert_prev;
different_sign = dp < 0.0f;
} else {
different_sign = !(dp < 0.0f);
}
if (different_sign) {
struct vertex_header *new_vert;
bool *new_edge;
assert(tmpnr < MAX_CLIPPED_VERTICES + 1);
if (tmpnr >= MAX_CLIPPED_VERTICES + 1)
return;
new_vert = clipper->stage.tmp[tmpnr++];
assert(outcount < MAX_CLIPPED_VERTICES);
if (outcount >= MAX_CLIPPED_VERTICES)
return;
new_edge = &outEdges[outcount];
outlist[outcount++] = new_vert;
float denom = dp - dp_prev;
if (dp < 0.0f) {
/* Going out of bounds. Avoid division by zero as we
* know dp != dp_prev from different_sign, above.
*/
if (-dp < dp_prev) {
float t = dp / denom;
interp(clipper, new_vert, t, vert, vert_prev, viewport_index);
} else {
float t = -dp_prev / denom;
interp(clipper, new_vert, t, vert_prev, vert, viewport_index);
}
/* Whether or not to set edge flag for the new vert depends
* on whether it's a user-defined clipping plane. We're
* copying NVIDIA's behaviour here.
*/
if (is_user_clip_plane) {
/* we want to see an edge along the clip plane */
*new_edge = true;
new_vert->edgeflag = true;
}
else {
/* we don't want to see an edge along the frustum clip plane */
*new_edge = *edge_prev;
new_vert->edgeflag = false;
}
}
else {
/* Coming back in.
*/
if (-dp_prev < dp) {
float t = -dp_prev / denom;
interp(clipper, new_vert, t, vert_prev, vert, viewport_index);
} else {
float t = dp / denom;
interp(clipper, new_vert, t, vert, vert_prev, viewport_index);
}
/* Copy starting vert's edgeflag:
*/
new_vert->edgeflag = vert_prev->edgeflag;
*new_edge = *edge_prev;
}
}
vert_prev = vert;
edge_prev = edge;
dp_prev = dp;
}
/* swap in/out lists */
SWAP(inlist, outlist);
SWAP(inEdges, outEdges);
n = outcount;
}
/* If constant interpolated, copy provoking vertex attrib to polygon vertex[0]
*/
if (n >= 3) {
if (clipper->num_const_attribs) {
if (stage->draw->rasterizer->flatshade_first) {
if (inlist[0] != header->v[0]) {
assert(tmpnr < MAX_CLIPPED_VERTICES + 1);
if (tmpnr >= MAX_CLIPPED_VERTICES + 1)
return;
inlist[0] = dup_vert(stage, inlist[0], tmpnr++);
copy_flat(stage, inlist[0], header->v[0]);
}
}
else {
if (inlist[0] != header->v[2]) {
assert(tmpnr < MAX_CLIPPED_VERTICES + 1);
if (tmpnr >= MAX_CLIPPED_VERTICES + 1)
return;
inlist[0] = dup_vert(stage, inlist[0], tmpnr++);
copy_flat(stage, inlist[0], header->v[2]);
}
}
}
/* Emit the polygon as triangles to the setup stage:
*/
emit_poly(stage, inlist, inEdges, n, header);
}
}
/* Clip a line against the viewport and user clip planes.
*/
static void
do_clip_line(struct draw_stage *stage,
struct prim_header *header,
unsigned clipmask)
{
const struct clip_stage *clipper = clip_stage(stage);
struct vertex_header *v0 = header->v[0];
struct vertex_header *v1 = header->v[1];
struct vertex_header *prov_vertex;
float t0 = 0.0F;
float t1 = 0.0F;
struct prim_header newprim;
int viewport_index;
newprim.flags = header->flags;
if (stage->draw->rasterizer->flatshade_first) {
prov_vertex = v0;
}
else {
prov_vertex = v1;
}
viewport_index = draw_viewport_index(clipper->stage.draw, prov_vertex);
while (clipmask) {
const unsigned plane_idx = ffs(clipmask)-1;
const float dp0 = getclipdist(clipper, v0, plane_idx);
const float dp1 = getclipdist(clipper, v1, plane_idx);
if (util_is_inf_or_nan(dp0) || util_is_inf_or_nan(dp1))
return; //discard nan
if (dp1 < 0.0F) {
float t = dp1 / (dp1 - dp0);
t1 = MAX2(t1, t);
}
if (dp0 < 0.0F) {
float t = dp0 / (dp0 - dp1);
t0 = MAX2(t0, t);
}
if (t0 + t1 >= 1.0F)
return; /* discard */
clipmask &= ~(1 << plane_idx); /* turn off this plane's bit */
}
if (v0->clipmask) {
interp(clipper, stage->tmp[0], t0, v0, v1, viewport_index);
if (stage->draw->rasterizer->flatshade_first) {
copy_flat(stage, stage->tmp[0], v0); /* copy v0 color to tmp[0] */
}
else {
copy_flat(stage, stage->tmp[0], v1); /* copy v1 color to tmp[0] */
}
newprim.v[0] = stage->tmp[0];
}
else {
newprim.v[0] = v0;
}
if (v1->clipmask) {
interp(clipper, stage->tmp[1], t1, v1, v0, viewport_index);
if (stage->draw->rasterizer->flatshade_first) {
copy_flat(stage, stage->tmp[1], v0); /* copy v0 color to tmp[1] */
}
else {
copy_flat(stage, stage->tmp[1], v1); /* copy v1 color to tmp[1] */
}
newprim.v[1] = stage->tmp[1];
}
else {
newprim.v[1] = v1;
}
stage->next->line(stage->next, &newprim);
}
static void
clip_point(struct draw_stage *stage, struct prim_header *header)
{
if (header->v[0]->clipmask == 0)
stage->next->point(stage->next, header);
}
/*
* Clip points but ignore the first 4 (xy) clip planes.
* (Because the generated clip mask is completely unaffacted by guard band,
* we still need to manually evaluate the x/y planes if they are outside
* the guard band and not just outside the vp.)
*/
static void
clip_point_guard_xy(struct draw_stage *stage, struct prim_header *header)
{
unsigned clipmask = header->v[0]->clipmask;
if ((clipmask & 0xffffffff) == 0)
stage->next->point(stage->next, header);
else if ((clipmask & 0xfffffff0) == 0) {
while (clipmask) {
const unsigned plane_idx = ffs(clipmask)-1;
clipmask &= ~(1 << plane_idx); /* turn off this plane's bit */
/* TODO: this should really do proper guardband clipping,
* currently just throw out infs/nans.
* Also note that vertices with negative w values MUST be tossed
* out (not sure if proper guardband clipping would do this
* automatically). These would usually be captured by depth clip
* too but this can be disabled.
*/
if (header->v[0]->clip_pos[3] <= 0.0f ||
util_is_inf_or_nan(header->v[0]->clip_pos[0]) ||
util_is_inf_or_nan(header->v[0]->clip_pos[1]))
return;
}
stage->next->point(stage->next, header);
}
}
static void
clip_first_point(struct draw_stage *stage, struct prim_header *header)
{
stage->point = stage->draw->guard_band_points_lines_xy ? clip_point_guard_xy : clip_point;
stage->point(stage, header);
}
static void
clip_line(struct draw_stage *stage, struct prim_header *header)
{
unsigned clipmask = (header->v[0]->clipmask |
header->v[1]->clipmask);
if (clipmask == 0) {
/* no clipping needed */
stage->next->line(stage->next, header);
}
else if ((header->v[0]->clipmask &
header->v[1]->clipmask) == 0) {
do_clip_line(stage, header, clipmask);
}
/* else, totally clipped */
}
static void
clip_line_guard_xy(struct draw_stage *stage, struct prim_header *header)
{
unsigned clipmask = (header->v[0]->clipmask |
header->v[1]->clipmask);
if ((clipmask & 0xffffffff) == 0) {
stage->next->line(stage->next, header);
}
else if ((clipmask & 0xfffffff0) == 0) {
while (clipmask) {
const unsigned plane_idx = ffs(clipmask)-1;
clipmask &= ~(1 << plane_idx); /* turn off this plane's bit */
/* TODO: this should really do proper guardband clipping,
* currently just throw out infs/nans.
* Also note that vertices with negative w values MUST be tossed
* out (not sure if proper guardband clipping would do this
* automatically). These would usually be captured by depth clip
* too but this can be disabled.
*/
if ((header->v[0]->clip_pos[3] <= 0.0f &&
header->v[1]->clip_pos[3] <= 0.0f) ||
util_is_nan(header->v[0]->clip_pos[0]) ||
util_is_nan(header->v[0]->clip_pos[1]) ||
util_is_nan(header->v[1]->clip_pos[0]) ||
util_is_nan(header->v[1]->clip_pos[1]))
return;
}
stage->next->line(stage->next, header);
} else if ((header->v[0]->clipmask &
header->v[1]->clipmask) == 0) {
do_clip_line(stage, header, clipmask & 0xfffffff0);
}
}
static void
clip_tri(struct draw_stage *stage, struct prim_header *header)
{
unsigned clipmask = (header->v[0]->clipmask |
header->v[1]->clipmask |
header->v[2]->clipmask);
if (clipmask == 0) {
/* no clipping needed */
stage->next->tri(stage->next, header);
}
else if ((header->v[0]->clipmask &
header->v[1]->clipmask &
header->v[2]->clipmask) == 0) {
do_clip_tri(stage, header, clipmask);
}
}
static enum tgsi_interpolate_mode
find_interp(const struct draw_fragment_shader *fs,
enum tgsi_interpolate_mode *indexed_interp,
enum tgsi_semantic semantic_name, unsigned semantic_index)
{
enum tgsi_interpolate_mode interp;
/* If it's gl_{Front,Back}{,Secondary}Color, pick up the mode
* from the array we've filled before. */
if ((semantic_name == TGSI_SEMANTIC_COLOR ||
semantic_name == TGSI_SEMANTIC_BCOLOR) &&
semantic_index < 2) {
interp = indexed_interp[semantic_index];
} else if (semantic_name == TGSI_SEMANTIC_POSITION ||
semantic_name == TGSI_SEMANTIC_CLIPVERTEX) {
/* these inputs are handled specially always */
return -1;
} else {
/* Otherwise, search in the FS inputs, with a decent default
* if we don't find it.
* This probably only matters for layer, vpindex, culldist, maybe
* front_face.
*/
unsigned j;
if (semantic_name == TGSI_SEMANTIC_LAYER ||
semantic_name == TGSI_SEMANTIC_VIEWPORT_INDEX) {
interp = TGSI_INTERPOLATE_CONSTANT;
}
else {
interp = TGSI_INTERPOLATE_PERSPECTIVE;
}
if (fs) {
for (j = 0; j < fs->info.num_inputs; j++) {
if (semantic_name == fs->info.input_semantic_name[j] &&
semantic_index == fs->info.input_semantic_index[j]) {
interp = fs->info.input_interpolate[j];
break;
}
}
}
}
return interp;
}
/* Update state. Could further delay this until we hit the first
* primitive that really requires clipping.
*/
static void
clip_init_state(struct draw_stage *stage)
{
struct clip_stage *clipper = clip_stage(stage);
const struct draw_context *draw = stage->draw;
const struct draw_fragment_shader *fs = draw->fs.fragment_shader;
const struct tgsi_shader_info *info = draw_get_shader_info(draw);
clipper->pos_attr = draw_current_shader_position_output(draw);
clipper->have_clipdist = draw_current_shader_num_written_clipdistances(draw) > 0;
if (draw_current_shader_clipvertex_output(draw) != clipper->pos_attr) {
clipper->cv_attr = (int)draw_current_shader_clipvertex_output(draw);
}
else {
clipper->cv_attr = -1;
}
/* We need to know for each attribute what kind of interpolation is
* done on it (flat, smooth or noperspective). But the information
* is not directly accessible for outputs, only for inputs. So we
* have to match semantic name and index between the VS (or GS/ES)
* outputs and the FS inputs to get to the interpolation mode.
*
* The only hitch is with gl_FrontColor/gl_BackColor which map to
* gl_Color, and their Secondary versions. First there are (up to)
* two outputs for one input, so we tuck the information in a
* specific array. Second if they don't have qualifiers, the
* default value has to be picked from the global shade mode.
*
* Of course, if we don't have a fragment shader in the first
* place, defaults should be used.
*/
/* First pick up the interpolation mode for
* gl_Color/gl_SecondaryColor, with the correct default.
*/
enum tgsi_interpolate_mode indexed_interp[2];
indexed_interp[0] = indexed_interp[1] = draw->rasterizer->flatshade ?
TGSI_INTERPOLATE_CONSTANT : TGSI_INTERPOLATE_PERSPECTIVE;
if (fs) {
for (unsigned i = 0; i < fs->info.num_inputs; i++) {
if (fs->info.input_semantic_name[i] == TGSI_SEMANTIC_COLOR &&
fs->info.input_semantic_index[i] < 2) {
if (fs->info.input_interpolate[i] != TGSI_INTERPOLATE_COLOR)
indexed_interp[fs->info.input_semantic_index[i]] = fs->info.input_interpolate[i];
}
}
}
/* Then resolve the interpolation mode for every output attribute. */
clipper->num_const_attribs = 0;
clipper->num_linear_attribs = 0;
clipper->num_perspect_attribs = 0;
unsigned i;
for (i = 0; i < info->num_outputs; i++) {
/* Find the interpolation mode for a specific attribute */
int interp = find_interp(fs, indexed_interp,
info->output_semantic_name[i],
info->output_semantic_index[i]);
switch (interp) {
case TGSI_INTERPOLATE_CONSTANT:
clipper->const_attribs[clipper->num_const_attribs] = i;
clipper->num_const_attribs++;
break;
case TGSI_INTERPOLATE_LINEAR:
clipper->linear_attribs[clipper->num_linear_attribs] = i;
clipper->num_linear_attribs++;
break;
case TGSI_INTERPOLATE_PERSPECTIVE:
clipper->perspect_attribs[clipper->num_perspect_attribs] = i;
clipper->num_perspect_attribs++;
break;
case TGSI_INTERPOLATE_COLOR:
if (draw->rasterizer->flatshade) {
clipper->const_attribs[clipper->num_const_attribs] = i;
clipper->num_const_attribs++;
} else {
clipper->perspect_attribs[clipper->num_perspect_attribs] = i;
clipper->num_perspect_attribs++;
}
break;
default:
assert(interp == -1);
break;
}
}
/* Search the extra vertex attributes */
for (unsigned j = 0; j < draw->extra_shader_outputs.num; j++) {
/* Find the interpolation mode for a specific attribute */
enum tgsi_interpolate_mode interp =
find_interp(fs, indexed_interp,
draw->extra_shader_outputs.semantic_name[j],
draw->extra_shader_outputs.semantic_index[j]);
switch (interp) {
case TGSI_INTERPOLATE_CONSTANT:
clipper->const_attribs[clipper->num_const_attribs] = i + j;
clipper->num_const_attribs++;
break;
case TGSI_INTERPOLATE_LINEAR:
clipper->linear_attribs[clipper->num_linear_attribs] = i + j;
clipper->num_linear_attribs++;
break;
case TGSI_INTERPOLATE_PERSPECTIVE:
clipper->perspect_attribs[clipper->num_perspect_attribs] = i + j;
clipper->num_perspect_attribs++;
break;
default:
assert(interp == -1);
break;
}
}
stage->tri = clip_tri;
}
static void
clip_first_tri(struct draw_stage *stage,
struct prim_header *header)
{
clip_init_state(stage);
stage->tri(stage, header);
}
static void
clip_first_line(struct draw_stage *stage,
struct prim_header *header)
{
clip_init_state(stage);
stage->line = stage->draw->guard_band_points_lines_xy ? clip_line_guard_xy : clip_line;
stage->line(stage, header);
}
static void
clip_flush(struct draw_stage *stage, unsigned flags)
{
stage->tri = clip_first_tri;
stage->line = clip_first_line;
stage->next->flush(stage->next, flags);
}
static void
clip_reset_stipple_counter(struct draw_stage *stage)
{
stage->next->reset_stipple_counter(stage->next);
}
static void
clip_destroy(struct draw_stage *stage)
{
draw_free_temp_verts(stage);
FREE(stage);
}
/**
* Allocate a new clipper stage.
* \return pointer to new stage object
*/
struct draw_stage *
draw_clip_stage(struct draw_context *draw)
{
struct clip_stage *clipper = CALLOC_STRUCT(clip_stage);
if (!clipper)
goto fail;
clipper->stage.draw = draw;
clipper->stage.name = "clipper";
clipper->stage.point = clip_first_point;
clipper->stage.line = clip_first_line;
clipper->stage.tri = clip_first_tri;
clipper->stage.flush = clip_flush;
clipper->stage.reset_stipple_counter = clip_reset_stipple_counter;
clipper->stage.destroy = clip_destroy;
clipper->plane = draw->plane;
if (!draw_alloc_temp_verts(&clipper->stage, MAX_CLIPPED_VERTICES+1))
goto fail;
return &clipper->stage;
fail:
if (clipper)
clipper->stage.destroy(&clipper->stage);
return NULL;
}
+171
View File
@@ -0,0 +1,171 @@
/**************************************************************************
*
* Copyright 2007 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 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 ITS 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.
*
**************************************************************************/
/**
* \brief Drawing stage for polygon culling
*/
/* Authors: Keith Whitwell <[email protected]>
*/
#include "util/u_math.h"
#include "util/u_memory.h"
#include "pipe/p_defines.h"
#include "draw_pipe.h"
struct cull_stage {
struct draw_stage stage;
unsigned cull_face; /**< which face(s) to cull (one of PIPE_FACE_x) */
unsigned front_ccw;
};
static inline struct cull_stage *
cull_stage(struct draw_stage *stage)
{
return (struct cull_stage *)stage;
}
/*
* Triangles can be culled using regular face cull.
*/
static void
cull_tri(struct draw_stage *stage,
struct prim_header *header)
{
const unsigned pos = draw_current_shader_position_output(stage->draw);
/* Window coords: */
const float *v0 = header->v[0]->data[pos];
const float *v1 = header->v[1]->data[pos];
const float *v2 = header->v[2]->data[pos];
/* edge vectors: e = v0 - v2, f = v1 - v2 */
const float ex = v0[0] - v2[0];
const float ey = v0[1] - v2[1];
const float fx = v1[0] - v2[0];
const float fy = v1[1] - v2[1];
/* det = cross(e,f).z */
header->det = ex * fy - ey * fx;
if (header->det != 0) {
/* if det < 0 then Z points toward the camera and the triangle is
* counter-clockwise winding.
*/
unsigned ccw = (header->det < 0);
unsigned face = ((ccw == cull_stage(stage)->front_ccw) ?
PIPE_FACE_FRONT :
PIPE_FACE_BACK);
if ((face & cull_stage(stage)->cull_face) == 0) {
/* triangle is not culled, pass to next stage */
stage->next->tri(stage->next, header);
}
} else {
/*
* With zero area, this is back facing (because the spec says
* it's front facing if sign is positive?).
* Some apis apparently do not allow us to cull zero area tris
* here, in case of fill mode line (which is rather lame).
*/
if ((PIPE_FACE_BACK & cull_stage(stage)->cull_face) == 0) {
stage->next->tri(stage->next, header);
}
}
}
static void
cull_first_tri(struct draw_stage *stage,
struct prim_header *header)
{
struct cull_stage *cull = cull_stage(stage);
cull->cull_face = stage->draw->rasterizer->cull_face;
cull->front_ccw = stage->draw->rasterizer->front_ccw;
stage->tri = cull_tri;
stage->tri(stage, header);
}
static void
cull_flush(struct draw_stage *stage, unsigned flags)
{
stage->tri = cull_first_tri;
stage->next->flush(stage->next, flags);
}
static void
cull_reset_stipple_counter(struct draw_stage *stage)
{
stage->next->reset_stipple_counter(stage->next);
}
static void
cull_destroy(struct draw_stage *stage)
{
draw_free_temp_verts(stage);
FREE(stage);
}
/**
* Create a new polygon culling stage.
*/
struct draw_stage *
draw_cull_stage(struct draw_context *draw)
{
struct cull_stage *cull = CALLOC_STRUCT(cull_stage);
if (!cull)
goto fail;
cull->stage.draw = draw;
cull->stage.name = "cull";
cull->stage.next = NULL;
cull->stage.point = draw_pipe_passthrough_point;
cull->stage.line = draw_pipe_passthrough_line;
cull->stage.tri = cull_first_tri;
cull->stage.flush = cull_flush;
cull->stage.reset_stipple_counter = cull_reset_stipple_counter;
cull->stage.destroy = cull_destroy;
if (!draw_alloc_temp_verts(&cull->stage, 0))
goto fail;
return &cull->stage;
fail:
if (cull)
cull->stage.destroy(&cull->stage);
return NULL;
}
@@ -0,0 +1,350 @@
/**************************************************************************
*
* Copyright 2007 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 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 ITS 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.
*
**************************************************************************/
/* Authors: Keith Whitwell <[email protected]>
*/
#include "util/u_math.h"
#include "util/u_memory.h"
#include "pipe/p_shader_tokens.h"
#include "draw_vs.h"
#include "draw_fs.h"
#include "draw_pipe.h"
/** subclass of draw_stage */
struct flat_stage
{
struct draw_stage stage;
unsigned num_flat_attribs;
unsigned flat_attribs[PIPE_MAX_SHADER_OUTPUTS]; /* flatshaded attribs */
};
static inline struct flat_stage *
flat_stage(struct draw_stage *stage)
{
return (struct flat_stage *) stage;
}
/** Copy all the constant attributes from 'src' vertex to 'dst' vertex */
static inline void
copy_flats(struct draw_stage *stage,
struct vertex_header *dst,
const struct vertex_header *src)
{
const struct flat_stage *flat = flat_stage(stage);
for (unsigned i = 0; i < flat->num_flat_attribs; i++) {
const unsigned attr = flat->flat_attribs[i];
COPY_4FV(dst->data[attr], src->data[attr]);
}
}
/** Copy all the color attributes from src vertex to dst0 & dst1 vertices */
static inline void
copy_flats2(struct draw_stage *stage,
struct vertex_header *dst0,
struct vertex_header *dst1,
const struct vertex_header *src)
{
const struct flat_stage *flat = flat_stage(stage);
for (unsigned i = 0; i < flat->num_flat_attribs; i++) {
const unsigned attr = flat->flat_attribs[i];
COPY_4FV(dst0->data[attr], src->data[attr]);
COPY_4FV(dst1->data[attr], src->data[attr]);
}
}
/**
* Flatshade tri. Not required for clipping which handles this on its own,
* but required for unfilled tris and other primitive-changing stages
* (like widelines). If no such stages are active, handled by hardware.
*/
static void
flatshade_tri_0(struct draw_stage *stage,
struct prim_header *header)
{
struct prim_header tmp;
tmp.det = header->det;
tmp.flags = header->flags;
tmp.pad = header->pad;
tmp.v[0] = header->v[0];
tmp.v[1] = dup_vert(stage, header->v[1], 0);
tmp.v[2] = dup_vert(stage, header->v[2], 1);
copy_flats2(stage, tmp.v[1], tmp.v[2], tmp.v[0]);
stage->next->tri(stage->next, &tmp);
}
static void
flatshade_tri_2(struct draw_stage *stage,
struct prim_header *header)
{
struct prim_header tmp;
tmp.det = header->det;
tmp.flags = header->flags;
tmp.pad = header->pad;
tmp.v[0] = dup_vert(stage, header->v[0], 0);
tmp.v[1] = dup_vert(stage, header->v[1], 1);
tmp.v[2] = header->v[2];
copy_flats2(stage, tmp.v[0], tmp.v[1], tmp.v[2]);
stage->next->tri(stage->next, &tmp);
}
/**
* Flatshade line.
*/
static void
flatshade_line_0(struct draw_stage *stage,
struct prim_header *header)
{
struct prim_header tmp;
tmp.det = header->det;
tmp.flags = header->flags;
tmp.pad = header->pad;
tmp.v[0] = header->v[0];
tmp.v[1] = dup_vert(stage, header->v[1], 0);
copy_flats(stage, tmp.v[1], tmp.v[0]);
stage->next->line(stage->next, &tmp);
}
static void
flatshade_line_1(struct draw_stage *stage,
struct prim_header *header)
{
struct prim_header tmp;
tmp.det = header->det;
tmp.flags = header->flags;
tmp.pad = header->pad;
tmp.v[0] = dup_vert(stage, header->v[0], 0);
tmp.v[1] = header->v[1];
copy_flats(stage, tmp.v[0], tmp.v[1]);
stage->next->line(stage->next, &tmp);
}
static int
find_interp(const struct draw_fragment_shader *fs, int *indexed_interp,
enum tgsi_semantic semantic_name, unsigned semantic_index)
{
int interp;
/* If it's gl_{Front,Back}{,Secondary}Color, pick up the mode
* from the array we've filled before. */
if ((semantic_name == TGSI_SEMANTIC_COLOR ||
semantic_name == TGSI_SEMANTIC_BCOLOR) &&
semantic_index < 2) {
interp = indexed_interp[semantic_index];
} else {
/* Otherwise, search in the FS inputs, with a decent default
* if we don't find it.
*/
interp = TGSI_INTERPOLATE_PERSPECTIVE;
if (fs) {
for (unsigned j = 0; j < fs->info.num_inputs; j++) {
if (semantic_name == fs->info.input_semantic_name[j] &&
semantic_index == fs->info.input_semantic_index[j]) {
interp = fs->info.input_interpolate[j];
break;
}
}
}
}
return interp;
}
static void
flatshade_init_state(struct draw_stage *stage)
{
struct flat_stage *flat = flat_stage(stage);
const struct draw_context *draw = stage->draw;
const struct draw_fragment_shader *fs = draw->fs.fragment_shader;
const struct tgsi_shader_info *info = draw_get_shader_info(draw);
unsigned i, j;
/* Find which vertex shader outputs need constant interpolation, make a list */
/* XXX: this code is a near exact copy of the one in clip_init_state.
* The latter also cares about perspective though.
*/
/* First pick up the interpolation mode for
* gl_Color/gl_SecondaryColor, with the correct default.
*/
int indexed_interp[2];
indexed_interp[0] = indexed_interp[1] = draw->rasterizer->flatshade ?
TGSI_INTERPOLATE_CONSTANT : TGSI_INTERPOLATE_PERSPECTIVE;
if (fs) {
for (i = 0; i < fs->info.num_inputs; i++) {
if (fs->info.input_semantic_name[i] == TGSI_SEMANTIC_COLOR &&
fs->info.input_semantic_index[i] < 2) {
if (fs->info.input_interpolate[i] != TGSI_INTERPOLATE_COLOR)
indexed_interp[fs->info.input_semantic_index[i]] = fs->info.input_interpolate[i];
}
}
}
/* Then resolve the interpolation mode for every output attribute.
*
* Given how the rest of the code, the most efficient way is to
* have a vector of flat-mode attributes.
*/
flat->num_flat_attribs = 0;
for (i = 0; i < info->num_outputs; i++) {
/* Find the interpolation mode for a specific attribute */
int interp = find_interp(fs, indexed_interp,
info->output_semantic_name[i],
info->output_semantic_index[i]);
/* If it's flat, add it to the flat vector. */
if (interp == TGSI_INTERPOLATE_CONSTANT ||
(interp == TGSI_INTERPOLATE_COLOR && draw->rasterizer->flatshade)) {
flat->flat_attribs[flat->num_flat_attribs] = i;
flat->num_flat_attribs++;
}
}
/* Search the extra vertex attributes */
for (j = 0; j < draw->extra_shader_outputs.num; j++) {
/* Find the interpolation mode for a specific attribute */
int interp = find_interp(fs, indexed_interp,
draw->extra_shader_outputs.semantic_name[j],
draw->extra_shader_outputs.semantic_index[j]);
/* If it's flat, add it to the flat vector. */
if (interp == TGSI_INTERPOLATE_CONSTANT) {
flat->flat_attribs[flat->num_flat_attribs] = i + j;
flat->num_flat_attribs++;
}
}
/* Choose flatshade routine according to provoking vertex:
*/
if (draw->rasterizer->flatshade_first) {
stage->line = flatshade_line_0;
stage->tri = flatshade_tri_0;
} else {
stage->line = flatshade_line_1;
stage->tri = flatshade_tri_2;
}
}
static void
flatshade_first_tri(struct draw_stage *stage,
struct prim_header *header)
{
flatshade_init_state(stage);
stage->tri(stage, header);
}
static void
flatshade_first_line(struct draw_stage *stage,
struct prim_header *header)
{
flatshade_init_state(stage);
stage->line(stage, header);
}
static void
flatshade_flush(struct draw_stage *stage,
unsigned flags)
{
stage->tri = flatshade_first_tri;
stage->line = flatshade_first_line;
stage->next->flush(stage->next, flags);
}
static void
flatshade_reset_stipple_counter(struct draw_stage *stage)
{
stage->next->reset_stipple_counter(stage->next);
}
static void
flatshade_destroy(struct draw_stage *stage)
{
draw_free_temp_verts(stage);
FREE(stage);
}
/**
* Create flatshading drawing stage.
*/
struct draw_stage *
draw_flatshade_stage(struct draw_context *draw)
{
struct flat_stage *flatshade = CALLOC_STRUCT(flat_stage);
if (!flatshade)
goto fail;
flatshade->stage.draw = draw;
flatshade->stage.name = "flatshade";
flatshade->stage.next = NULL;
flatshade->stage.point = draw_pipe_passthrough_point;
flatshade->stage.line = flatshade_first_line;
flatshade->stage.tri = flatshade_first_tri;
flatshade->stage.flush = flatshade_flush;
flatshade->stage.reset_stipple_counter = flatshade_reset_stipple_counter;
flatshade->stage.destroy = flatshade_destroy;
if (!draw_alloc_temp_verts(&flatshade->stage, 2))
goto fail;
return &flatshade->stage;
fail:
if (flatshade)
flatshade->stage.destroy(&flatshade->stage);
return NULL;
}
@@ -0,0 +1,255 @@
/**************************************************************************
*
* Copyright 2007 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 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 ITS 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.
*
**************************************************************************/
/**
* \brief polygon offset state
*
* \author Keith Whitwell <[email protected]>
* \author Brian Paul
*/
#include "util/format/u_format.h"
#include "util/u_math.h"
#include "util/u_memory.h"
#include "draw_pipe.h"
struct offset_stage {
struct draw_stage stage;
float scale;
float units;
float clamp;
};
static inline struct offset_stage *
offset_stage(struct draw_stage *stage)
{
return (struct offset_stage *) stage;
}
/**
* Offset tri Z. Some hardware can handle this, but not usually when
* doing unfilled rendering.
*/
static void
do_offset_tri(struct draw_stage *stage,
struct prim_header *header)
{
const unsigned pos = draw_current_shader_position_output(stage->draw);
struct offset_stage *offset = offset_stage(stage);
float inv_det = 1.0f / header->det;
/* Window coords:
*/
float *v0 = header->v[0]->data[pos];
float *v1 = header->v[1]->data[pos];
float *v2 = header->v[2]->data[pos];
/* edge vectors e = v0 - v2, f = v1 - v2 */
float ex = v0[0] - v2[0];
float ey = v0[1] - v2[1];
float ez = v0[2] - v2[2];
float fx = v1[0] - v2[0];
float fy = v1[1] - v2[1];
float fz = v1[2] - v2[2];
/* (a,b) = cross(e,f).xy */
float a = ey*fz - ez*fy;
float b = ez*fx - ex*fz;
float dzdx = fabsf(a * inv_det);
float dzdy = fabsf(b * inv_det);
float mult = MAX2(dzdx, dzdy) * offset->scale;
float zoffset;
if (stage->draw->floating_point_depth) {
float bias;
union fi maxz;
maxz.f = MAX3(fabs(v0[2]), fabs(v1[2]), fabs(v2[2]));
/* just do the math directly on shifted number */
maxz.ui &= 0xff << 23;
maxz.i -= 23 << 23;
/* Clamping to zero means mrd will be zero for very small numbers,
* but specs do not indicate this should be prevented by clamping
* mrd to smallest normal number instead. */
maxz.i = MAX2(maxz.i, 0);
bias = offset->units * maxz.f;
zoffset = bias + mult;
} else {
zoffset = offset->units + mult;
}
if (offset->clamp)
zoffset = (offset->clamp < 0.0f) ? MAX2(zoffset, offset->clamp) :
MIN2(zoffset, offset->clamp);
/*
* Note: we're applying the offset and clamping per-vertex.
* Ideally, the offset is applied per-fragment prior to fragment shading.
*/
v0[2] = SATURATE(v0[2] + zoffset);
v1[2] = SATURATE(v1[2] + zoffset);
v2[2] = SATURATE(v2[2] + zoffset);
stage->next->tri(stage->next, header);
}
static void
offset_tri(struct draw_stage *stage,
struct prim_header *header)
{
struct prim_header tmp;
tmp.det = header->det;
tmp.flags = header->flags;
tmp.pad = header->pad;
tmp.v[0] = dup_vert(stage, header->v[0], 0);
tmp.v[1] = dup_vert(stage, header->v[1], 1);
tmp.v[2] = dup_vert(stage, header->v[2], 2);
do_offset_tri(stage, &tmp);
}
static void
offset_first_tri(struct draw_stage *stage,
struct prim_header *header)
{
struct offset_stage *offset = offset_stage(stage);
const struct pipe_rasterizer_state *rast = stage->draw->rasterizer;
unsigned fill_mode = rast->fill_front;
bool do_offset;
if (rast->fill_back != rast->fill_front) {
/* Need to check for back-facing triangle */
bool ccw = header->det < 0.0f;
if (ccw != rast->front_ccw)
fill_mode = rast->fill_back;
}
/* Now determine if we need to do offsetting for the point/line/fill mode */
switch (fill_mode) {
case PIPE_POLYGON_MODE_FILL:
do_offset = rast->offset_tri;
break;
case PIPE_POLYGON_MODE_LINE:
do_offset = rast->offset_line;
break;
case PIPE_POLYGON_MODE_POINT:
do_offset = rast->offset_point;
break;
default:
assert(!"invalid fill_mode in offset_first_tri()");
do_offset = rast->offset_tri;
}
if (do_offset) {
offset->scale = rast->offset_scale;
offset->clamp = rast->offset_clamp;
/*
* If depth is floating point, depth bias is calculated with respect
* to the primitive's maximum Z value. Retain the original depth bias
* value until that stage.
*/
if (stage->draw->floating_point_depth) {
offset->units = (float) rast->offset_units;
} else {
offset->units = (float) (rast->offset_units * stage->draw->mrd * 2);
}
} else {
offset->scale = 0.0f;
offset->clamp = 0.0f;
offset->units = 0.0f;
}
stage->tri = offset_tri;
stage->tri(stage, header);
}
static void
offset_flush(struct draw_stage *stage,
unsigned flags)
{
stage->tri = offset_first_tri;
stage->next->flush(stage->next, flags);
}
static void
offset_reset_stipple_counter(struct draw_stage *stage)
{
stage->next->reset_stipple_counter(stage->next);
}
static void
offset_destroy(struct draw_stage *stage)
{
draw_free_temp_verts(stage);
FREE(stage);
}
/**
* Create polygon offset drawing stage.
*/
struct draw_stage *
draw_offset_stage(struct draw_context *draw)
{
struct offset_stage *offset = CALLOC_STRUCT(offset_stage);
if (!offset)
goto fail;
offset->stage.draw = draw;
offset->stage.name = "offset";
offset->stage.next = NULL;
offset->stage.point = draw_pipe_passthrough_point;
offset->stage.line = draw_pipe_passthrough_line;
offset->stage.tri = offset_first_tri;
offset->stage.flush = offset_flush;
offset->stage.reset_stipple_counter = offset_reset_stipple_counter;
offset->stage.destroy = offset_destroy;
if (!draw_alloc_temp_verts(&offset->stage, 3))
goto fail;
return &offset->stage;
fail:
if (offset)
offset->stage.destroy(&offset->stage);
return NULL;
}
@@ -0,0 +1,516 @@
/**************************************************************************
*
* Copyright 2008 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 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 ITS 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.
*
**************************************************************************/
/**
* Polygon stipple stage: implement polygon stipple with texture map and
* fragment program. The fragment program samples the texture using the
* fragment window coordinate register and does a fragment kill for the
* stipple-failing fragments.
*
* Authors: Brian Paul
*/
#include "pipe/p_context.h"
#include "pipe/p_defines.h"
#include "pipe/p_shader_tokens.h"
#include "util/u_inlines.h"
#include "util/format/u_format.h"
#include "util/u_math.h"
#include "util/u_memory.h"
#include "util/u_pstipple.h"
#include "util/u_sampler.h"
#include "tgsi/tgsi_parse.h"
#include "draw_context.h"
#include "draw_pipe.h"
#include "nir.h"
#include "nir/nir_draw_helpers.h"
/** Approx number of new tokens for instructions in pstip_transform_inst() */
#define NUM_NEW_TOKENS 53
/**
* Subclass of pipe_shader_state to carry extra fragment shader info.
*/
struct pstip_fragment_shader
{
struct pipe_shader_state state;
void *driver_fs;
void *pstip_fs;
unsigned sampler_unit;
};
/**
* Subclass of draw_stage
*/
struct pstip_stage
{
struct draw_stage stage;
void *sampler_cso;
struct pipe_resource *texture;
struct pipe_sampler_view *sampler_view;
unsigned num_samplers;
unsigned num_sampler_views;
/*
* Currently bound state
*/
struct pstip_fragment_shader *fs;
struct {
void *samplers[PIPE_MAX_SAMPLERS];
struct pipe_sampler_view *sampler_views[PIPE_MAX_SHADER_SAMPLER_VIEWS];
const struct pipe_poly_stipple *stipple;
} state;
/*
* Driver interface/override functions
*/
void * (*driver_create_fs_state)(struct pipe_context *,
const struct pipe_shader_state *);
void (*driver_bind_fs_state)(struct pipe_context *, void *);
void (*driver_delete_fs_state)(struct pipe_context *, void *);
void (*driver_bind_sampler_states)(struct pipe_context *,
mesa_shader_stage,
unsigned, unsigned, void **);
void (*driver_set_sampler_views)(struct pipe_context *,
mesa_shader_stage shader,
unsigned start, unsigned count,
unsigned unbind_num_trailing_slots,
struct pipe_sampler_view **);
void (*driver_set_polygon_stipple)(struct pipe_context *,
const struct pipe_poly_stipple *);
struct pipe_context *pipe;
};
/**
* Generate the frag shader we'll use for doing polygon stipple.
* This will be the user's shader prefixed with a TEX and KIL instruction.
*/
static bool
generate_pstip_fs(struct pstip_stage *pstip)
{
struct pipe_context *pipe = pstip->pipe;
struct pipe_screen *screen = pipe->screen;
const struct pipe_shader_state *orig_fs = &pstip->fs->state;
/*struct draw_context *draw = pstip->stage.draw;*/
struct pipe_shader_state pstip_fs;
enum tgsi_file_type wincoord_file;
wincoord_file = screen->caps.fs_position_is_sysval ?
TGSI_FILE_SYSTEM_VALUE : TGSI_FILE_INPUT;
pstip_fs = *orig_fs; /* copy to init */
if (orig_fs->type == PIPE_SHADER_IR_TGSI) {
pstip_fs.tokens = util_pstipple_create_fragment_shader(orig_fs->tokens,
&pstip->fs->sampler_unit,
0,
wincoord_file);
if (pstip_fs.tokens == NULL)
return false;
} else {
pstip_fs.ir.nir = nir_shader_clone(NULL, orig_fs->ir.nir);
nir_lower_pstipple_fs(pstip_fs.ir.nir,
&pstip->fs->sampler_unit, 0, wincoord_file == TGSI_FILE_SYSTEM_VALUE,
nir_type_bool1);
}
assert(pstip->fs->sampler_unit < PIPE_MAX_SAMPLERS);
pstip->fs->pstip_fs = pstip->driver_create_fs_state(pipe, &pstip_fs);
FREE((void *)pstip_fs.tokens);
if (!pstip->fs->pstip_fs)
return false;
return true;
}
/**
* When we're about to draw our first stipple polygon in a batch, this function
* is called to tell the driver to bind our modified fragment shader.
*/
static bool
bind_pstip_fragment_shader(struct pstip_stage *pstip)
{
struct draw_context *draw = pstip->stage.draw;
if (!pstip->fs->pstip_fs &&
!generate_pstip_fs(pstip))
return false;
draw->suspend_flushing = true;
pstip->driver_bind_fs_state(pstip->pipe, pstip->fs->pstip_fs);
draw->suspend_flushing = false;
return true;
}
static inline struct pstip_stage *
pstip_stage(struct draw_stage *stage)
{
return (struct pstip_stage *) stage;
}
static void
pstip_first_tri(struct draw_stage *stage, struct prim_header *header)
{
struct pstip_stage *pstip = pstip_stage(stage);
struct pipe_context *pipe = pstip->pipe;
struct draw_context *draw = stage->draw;
unsigned num_samplers;
unsigned num_sampler_views;
assert(stage->draw->rasterizer->poly_stipple_enable);
/* bind our fragprog */
if (!bind_pstip_fragment_shader(pstip)) {
stage->tri = draw_pipe_passthrough_tri;
stage->tri(stage, header);
return;
}
/* how many samplers? */
/* we'll use sampler/texture[pstip->sampler_unit] for the stipple */
num_samplers = MAX2(pstip->num_samplers, pstip->fs->sampler_unit + 1);
num_sampler_views = MAX2(pstip->num_sampler_views, num_samplers);
/* plug in our sampler, texture */
pstip->state.samplers[pstip->fs->sampler_unit] = pstip->sampler_cso;
pstip->state.sampler_views[pstip->fs->sampler_unit] = pstip->sampler_view;
assert(num_samplers <= PIPE_MAX_SAMPLERS);
draw->suspend_flushing = true;
pstip->driver_bind_sampler_states(pipe, MESA_SHADER_FRAGMENT, 0,
num_samplers, pstip->state.samplers);
pstip->driver_set_sampler_views(pipe, MESA_SHADER_FRAGMENT, 0,
num_sampler_views, 0,
pstip->state.sampler_views);
draw->suspend_flushing = false;
/* now really draw first triangle */
stage->tri = draw_pipe_passthrough_tri;
stage->tri(stage, header);
}
static void
pstip_flush(struct draw_stage *stage, unsigned flags)
{
struct draw_context *draw = stage->draw;
struct pstip_stage *pstip = pstip_stage(stage);
struct pipe_context *pipe = pstip->pipe;
stage->tri = pstip_first_tri;
stage->next->flush(stage->next, flags);
/* restore original frag shader, texture, sampler state */
draw->suspend_flushing = true;
pstip->driver_bind_fs_state(pipe, pstip->fs ? pstip->fs->driver_fs : NULL);
pstip->driver_bind_sampler_states(pipe, MESA_SHADER_FRAGMENT, 0,
pstip->num_samplers,
pstip->state.samplers);
pstip->driver_set_sampler_views(pipe, MESA_SHADER_FRAGMENT, 0,
pstip->num_sampler_views, 0,
pstip->state.sampler_views);
draw->suspend_flushing = false;
}
static void
pstip_reset_stipple_counter(struct draw_stage *stage)
{
stage->next->reset_stipple_counter(stage->next);
}
static void
pstip_destroy(struct draw_stage *stage)
{
struct pstip_stage *pstip = pstip_stage(stage);
for (unsigned i = 0; i < PIPE_MAX_SHADER_SAMPLER_VIEWS; i++) {
pipe_sampler_view_reference(&pstip->state.sampler_views[i], NULL);
}
pstip->pipe->delete_sampler_state(pstip->pipe, pstip->sampler_cso);
pipe_resource_reference(&pstip->texture, NULL);
pipe_sampler_view_release_ptr(&pstip->sampler_view);
draw_free_temp_verts(stage);
FREE(stage);
}
/** Create a new polygon stipple drawing stage object */
static struct pstip_stage *
draw_pstip_stage(struct draw_context *draw, struct pipe_context *pipe)
{
struct pstip_stage *pstip = CALLOC_STRUCT(pstip_stage);
if (!pstip)
goto fail;
pstip->pipe = pipe;
pstip->stage.draw = draw;
pstip->stage.name = "pstip";
pstip->stage.next = NULL;
pstip->stage.point = draw_pipe_passthrough_point;
pstip->stage.line = draw_pipe_passthrough_line;
pstip->stage.tri = pstip_first_tri;
pstip->stage.flush = pstip_flush;
pstip->stage.reset_stipple_counter = pstip_reset_stipple_counter;
pstip->stage.destroy = pstip_destroy;
if (!draw_alloc_temp_verts(&pstip->stage, 8))
goto fail;
return pstip;
fail:
if (pstip)
pstip->stage.destroy(&pstip->stage);
return NULL;
}
static struct pstip_stage *
pstip_stage_from_pipe(struct pipe_context *pipe)
{
struct draw_context *draw = (struct draw_context *) pipe->draw;
return pstip_stage(draw->pipeline.pstipple);
}
/**
* This function overrides the driver's create_fs_state() function and
* will typically be called by the gallium frontend.
*/
static void *
pstip_create_fs_state(struct pipe_context *pipe,
const struct pipe_shader_state *fs)
{
struct pstip_stage *pstip = pstip_stage_from_pipe(pipe);
struct pstip_fragment_shader *pstipfs = CALLOC_STRUCT(pstip_fragment_shader);
if (pstipfs) {
pstipfs->state.type = fs->type;
if (fs->type == PIPE_SHADER_IR_TGSI)
pstipfs->state.tokens = tgsi_dup_tokens(fs->tokens);
else
pstipfs->state.ir.nir = nir_shader_clone(NULL, fs->ir.nir);
/* pass-through */
pstipfs->driver_fs = pstip->driver_create_fs_state(pstip->pipe, fs);
}
return pstipfs;
}
static void
pstip_bind_fs_state(struct pipe_context *pipe, void *fs)
{
struct pstip_stage *pstip = pstip_stage_from_pipe(pipe);
struct pstip_fragment_shader *pstipfs = (struct pstip_fragment_shader *) fs;
/* save current */
pstip->fs = pstipfs;
/* pass-through */
pstip->driver_bind_fs_state(pstip->pipe,
(pstipfs ? pstipfs->driver_fs : NULL));
}
static void
pstip_delete_fs_state(struct pipe_context *pipe, void *fs)
{
struct pstip_stage *pstip = pstip_stage_from_pipe(pipe);
struct pstip_fragment_shader *pstipfs = (struct pstip_fragment_shader *) fs;
/* pass-through */
pstip->driver_delete_fs_state(pstip->pipe, pstipfs->driver_fs);
if (pstipfs->pstip_fs)
pstip->driver_delete_fs_state(pstip->pipe, pstipfs->pstip_fs);
if (pstipfs->state.type == PIPE_SHADER_IR_TGSI)
FREE((void*)pstipfs->state.tokens);
else
ralloc_free(pstipfs->state.ir.nir);
FREE(pstipfs);
}
static void
pstip_bind_sampler_states(struct pipe_context *pipe,
mesa_shader_stage shader,
unsigned start, unsigned num, void **sampler)
{
struct pstip_stage *pstip = pstip_stage_from_pipe(pipe);
assert(start == 0);
if (shader == MESA_SHADER_FRAGMENT) {
/* save current */
memcpy(pstip->state.samplers, sampler, num * sizeof(void *));
for (unsigned i = num; i < PIPE_MAX_SAMPLERS; i++) {
pstip->state.samplers[i] = NULL;
}
pstip->num_samplers = num;
}
/* pass-through */
pstip->driver_bind_sampler_states(pstip->pipe, shader, start, num, sampler);
}
static void
pstip_set_sampler_views(struct pipe_context *pipe,
mesa_shader_stage shader,
unsigned start, unsigned num,
unsigned unbind_num_trailing_slots,
struct pipe_sampler_view **views)
{
struct pstip_stage *pstip = pstip_stage_from_pipe(pipe);
if (shader == MESA_SHADER_FRAGMENT) {
/* save current */
unsigned i;
for (i = 0; i < num; i++) {
pstip->state.sampler_views[start + i] = views[i];
}
for (; i < num + unbind_num_trailing_slots; i++) {
pstip->state.sampler_views[start + i] = NULL;
}
pstip->num_sampler_views = num;
}
/* pass-through */
pstip->driver_set_sampler_views(pstip->pipe, shader, start, num,
unbind_num_trailing_slots, views);
}
static void
pstip_set_polygon_stipple(struct pipe_context *pipe,
const struct pipe_poly_stipple *stipple)
{
struct pstip_stage *pstip = pstip_stage_from_pipe(pipe);
/* save current */
pstip->state.stipple = stipple;
/* pass-through */
pstip->driver_set_polygon_stipple(pstip->pipe, stipple);
util_pstipple_update_stipple_texture(pstip->pipe, pstip->texture,
pstip->state.stipple->stipple);
}
/**
* Called by drivers that want to install this polygon stipple stage
* into the draw module's pipeline. This will not be used if the
* hardware has native support for polygon stipple.
*/
bool
draw_install_pstipple_stage(struct draw_context *draw,
struct pipe_context *pipe)
{
pipe->draw = (void *) draw;
/*
* Create / install pgon stipple drawing / prim stage
*/
struct pstip_stage *pstip = draw_pstip_stage(draw, pipe);
if (!pstip)
goto fail;
draw->pipeline.pstipple = &pstip->stage;
/* save original driver functions */
pstip->driver_create_fs_state = pipe->create_fs_state;
pstip->driver_bind_fs_state = pipe->bind_fs_state;
pstip->driver_delete_fs_state = pipe->delete_fs_state;
pstip->driver_bind_sampler_states = pipe->bind_sampler_states;
pstip->driver_set_sampler_views = pipe->set_sampler_views;
pstip->driver_set_polygon_stipple = pipe->set_polygon_stipple;
/* create special texture, sampler state */
pstip->texture = util_pstipple_create_stipple_texture(pipe, NULL);
if (!pstip->texture)
goto fail;
pstip->sampler_view = util_pstipple_create_sampler_view(pipe,
pstip->texture);
if (!pstip->sampler_view)
goto fail;
pstip->sampler_cso = util_pstipple_create_sampler(pipe);
if (!pstip->sampler_cso)
goto fail;
/* override the driver's functions */
pipe->create_fs_state = pstip_create_fs_state;
pipe->bind_fs_state = pstip_bind_fs_state;
pipe->delete_fs_state = pstip_delete_fs_state;
pipe->bind_sampler_states = pstip_bind_sampler_states;
pipe->set_sampler_views = pstip_set_sampler_views;
pipe->set_polygon_stipple = pstip_set_polygon_stipple;
return true;
fail:
if (pstip)
pstip->stage.destroy(&pstip->stage);
return false;
}
@@ -0,0 +1,272 @@
/**************************************************************************
*
* Copyright 2007 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 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 ITS 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.
*
**************************************************************************/
/* Authors: Keith Whitwell <[email protected]>
*/
/* Implement line stipple by cutting lines up into smaller lines.
* There are hundreds of ways to implement line stipple, this is one
* choice that should work in all situations, requires no state
* manipulations, but with a penalty in terms of large amounts of
* generated geometry.
*/
#include "pipe/p_defines.h"
#include "pipe/p_shader_tokens.h"
#include "util/u_math.h"
#include "util/u_memory.h"
#include "draw/draw_pipe.h"
/** Subclass of draw_stage */
struct stipple_stage {
struct draw_stage stage;
unsigned counter;
uint16_t pattern;
uint16_t factor;
bool rectangular;
};
static inline struct stipple_stage *
stipple_stage(struct draw_stage *stage)
{
return (struct stipple_stage *) stage;
}
/**
* Compute interpolated vertex attributes for 'dst' at position 't'
* between 'v0' and 'v1'.
* XXX using linear interpolation for all attribs at this time.
*/
static void
screen_interp(struct draw_context *draw,
struct vertex_header *dst,
float t,
const struct vertex_header *v0,
const struct vertex_header *v1)
{
unsigned attr;
unsigned num_outputs = draw_current_shader_outputs(draw);
for (attr = 0; attr < num_outputs; attr++) {
const float *val0 = v0->data[attr];
const float *val1 = v1->data[attr];
float *newv = dst->data[attr];
unsigned i;
for (i = 0; i < 4; i++) {
newv[i] = val0[i] + t * (val1[i] - val0[i]);
}
}
}
static void
emit_segment(struct draw_stage *stage, struct prim_header *header,
float t0, float t1)
{
struct vertex_header *v0new = dup_vert(stage, header->v[0], 0);
struct vertex_header *v1new = dup_vert(stage, header->v[1], 1);
struct prim_header newprim = *header;
if (t0 > 0.0) {
screen_interp(stage->draw, v0new, t0, header->v[0], header->v[1]);
newprim.v[0] = v0new;
}
if (t1 < 1.0) {
screen_interp(stage->draw, v1new, t1, header->v[0], header->v[1]);
newprim.v[1] = v1new;
}
stage->next->line(stage->next, &newprim);
}
static inline bool
stipple_test(unsigned counter, uint16_t pattern, uint16_t factor)
{
unsigned b = (counter / factor) & 0xf;
return !!((1 << b) & pattern);
}
static void
stipple_line(struct draw_stage *stage, struct prim_header *header)
{
struct stipple_stage *stipple = stipple_stage(stage);
struct vertex_header *v0 = header->v[0];
struct vertex_header *v1 = header->v[1];
const unsigned pos = draw_current_shader_position_output(stage->draw);
const float *pos0 = v0->data[pos];
const float *pos1 = v1->data[pos];
float start = 0;
bool state = 0;
float x0 = pos0[0];
float x1 = pos1[0];
float y0 = pos0[1];
float y1 = pos1[1];
float length;
int i;
int intlength;
if (header->flags & DRAW_PIPE_RESET_STIPPLE)
stipple->counter = 0;
if (stipple->rectangular) {
float dx = x1 - x0;
float dy = y1 - y0;
length = sqrtf(dx*dx + dy*dy);
} else {
float dx = x0 > x1 ? x0 - x1 : x1 - x0;
float dy = y0 > y1 ? y0 - y1 : y1 - y0;
length = MAX2(dx, dy);
}
if (util_is_inf_or_nan(length))
intlength = 0;
else
intlength = ceilf(length);
/* XXX ToDo: instead of iterating pixel-by-pixel, use a look-up table.
*/
for (i = 0; i < intlength; i++) {
bool result = stipple_test(stipple->counter + i,
stipple->pattern, stipple->factor);
if (result != state) {
/* changing from "off" to "on" or vice versa */
if (state) {
/* finishing an "on" segment */
emit_segment(stage, header, start / length, i / length);
}
else {
/* starting an "on" segment */
start = (float)i;
}
state = result;
}
}
if (state && start < length)
emit_segment(stage, header, start / length, 1.0);
stipple->counter += intlength;
}
static void
reset_stipple_counter(struct draw_stage *stage)
{
struct stipple_stage *stipple = stipple_stage(stage);
stipple->counter = 0;
stage->next->reset_stipple_counter(stage->next);
}
static void
stipple_reset_point(struct draw_stage *stage, struct prim_header *header)
{
struct stipple_stage *stipple = stipple_stage(stage);
stipple->counter = 0;
stage->next->point(stage->next, header);
}
static void
stipple_reset_tri(struct draw_stage *stage, struct prim_header *header)
{
struct stipple_stage *stipple = stipple_stage(stage);
stipple->counter = 0;
stage->next->tri(stage->next, header);
}
static void
stipple_first_line(struct draw_stage *stage,
struct prim_header *header)
{
struct stipple_stage *stipple = stipple_stage(stage);
struct draw_context *draw = stage->draw;
stipple->pattern = draw->rasterizer->line_stipple_pattern;
stipple->factor = draw->rasterizer->line_stipple_factor + 1;
stipple->rectangular = draw->rasterizer->line_rectangular;
stage->line = stipple_line;
stage->line(stage, header);
}
static void
stipple_flush(struct draw_stage *stage, unsigned flags)
{
stage->line = stipple_first_line;
stage->next->flush(stage->next, flags);
}
static void
stipple_destroy(struct draw_stage *stage)
{
draw_free_temp_verts(stage);
FREE(stage);
}
/**
* Create line stippler stage
*/
struct draw_stage *
draw_stipple_stage(struct draw_context *draw)
{
struct stipple_stage *stipple = CALLOC_STRUCT(stipple_stage);
if (!stipple)
goto fail;
stipple->stage.draw = draw;
stipple->stage.name = "stipple";
stipple->stage.next = NULL;
stipple->stage.point = stipple_reset_point;
stipple->stage.line = stipple_first_line;
stipple->stage.tri = stipple_reset_tri;
stipple->stage.reset_stipple_counter = reset_stipple_counter;
stipple->stage.flush = stipple_flush;
stipple->stage.destroy = stipple_destroy;
if (!draw_alloc_temp_verts(&stipple->stage, 2))
goto fail;
return &stipple->stage;
fail:
if (stipple)
stipple->stage.destroy(&stipple->stage);
return NULL;
}
@@ -0,0 +1,199 @@
/**************************************************************************
*
* Copyright 2007 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 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 ITS 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.
*
**************************************************************************/
/* Authors: Keith Whitwell <[email protected]>
*/
#include "util/u_math.h"
#include "util/u_memory.h"
#include "pipe/p_defines.h"
#include "pipe/p_shader_tokens.h"
#include "draw_vs.h"
#include "draw_pipe.h"
struct twoside_stage {
struct draw_stage stage;
float sign; /**< +1 or -1 */
int attrib_front0, attrib_back0;
int attrib_front1, attrib_back1;
};
static inline struct twoside_stage *
twoside_stage(struct draw_stage *stage)
{
return (struct twoside_stage *) stage;
}
/**
* Copy back color(s) to front color(s).
*/
static inline struct vertex_header *
copy_bfc(struct twoside_stage *twoside,
const struct vertex_header *v,
unsigned idx)
{
struct vertex_header *tmp = dup_vert(&twoside->stage, v, idx);
if (twoside->attrib_back0 >= 0 && twoside->attrib_front0 >= 0) {
COPY_4FV(tmp->data[twoside->attrib_front0],
tmp->data[twoside->attrib_back0]);
}
if (twoside->attrib_back1 >= 0 && twoside->attrib_front1 >= 0) {
COPY_4FV(tmp->data[twoside->attrib_front1],
tmp->data[twoside->attrib_back1]);
}
return tmp;
}
/* Twoside tri:
*/
static void
twoside_tri(struct draw_stage *stage,
struct prim_header *header)
{
struct twoside_stage *twoside = twoside_stage(stage);
if (header->det * twoside->sign < 0.0) {
/* this is a back-facing triangle */
struct prim_header tmp;
tmp.det = header->det;
tmp.flags = header->flags;
tmp.pad = header->pad;
/* copy back attribs to front attribs */
tmp.v[0] = copy_bfc(twoside, header->v[0], 0);
tmp.v[1] = copy_bfc(twoside, header->v[1], 1);
tmp.v[2] = copy_bfc(twoside, header->v[2], 2);
stage->next->tri(stage->next, &tmp);
} else {
stage->next->tri(stage->next, header);
}
}
static void
twoside_first_tri(struct draw_stage *stage,
struct prim_header *header)
{
struct twoside_stage *twoside = twoside_stage(stage);
const struct draw_vertex_shader *vs = stage->draw->vs.vertex_shader;
twoside->attrib_front0 = -1;
twoside->attrib_front1 = -1;
twoside->attrib_back0 = -1;
twoside->attrib_back1 = -1;
/*
* Find which vertex shader outputs are front/back colors
* (only first two can be front or back).
*/
for (unsigned i = 0; i < vs->info.num_outputs; i++) {
if (vs->info.output_semantic_name[i] == TGSI_SEMANTIC_COLOR) {
if (vs->info.output_semantic_index[i] == 0)
twoside->attrib_front0 = i;
else if (vs->info.output_semantic_index[i] == 1)
twoside->attrib_front1 = i;
}
if (vs->info.output_semantic_name[i] == TGSI_SEMANTIC_BCOLOR) {
if (vs->info.output_semantic_index[i] == 0)
twoside->attrib_back0 = i;
else if (vs->info.output_semantic_index[i] == 1)
twoside->attrib_back1 = i;
}
}
/*
* We'll multiply the primitive's determinant by this sign to determine
* if the triangle is back-facing (negative).
* sign = -1 for CCW, +1 for CW
*/
twoside->sign = stage->draw->rasterizer->front_ccw ? -1.0f : 1.0f;
stage->tri = twoside_tri;
stage->tri(stage, header);
}
static void
twoside_flush(struct draw_stage *stage, unsigned flags)
{
stage->tri = twoside_first_tri;
stage->next->flush(stage->next, flags);
}
static void
twoside_reset_stipple_counter(struct draw_stage *stage)
{
stage->next->reset_stipple_counter(stage->next);
}
static void
twoside_destroy(struct draw_stage *stage)
{
draw_free_temp_verts(stage);
FREE(stage);
}
/**
* Create twoside pipeline stage.
*/
struct draw_stage *
draw_twoside_stage(struct draw_context *draw)
{
struct twoside_stage *twoside = CALLOC_STRUCT(twoside_stage);
if (!twoside)
goto fail;
twoside->stage.draw = draw;
twoside->stage.name = "twoside";
twoside->stage.next = NULL;
twoside->stage.point = draw_pipe_passthrough_point;
twoside->stage.line = draw_pipe_passthrough_line;
twoside->stage.tri = twoside_first_tri;
twoside->stage.flush = twoside_flush;
twoside->stage.reset_stipple_counter = twoside_reset_stipple_counter;
twoside->stage.destroy = twoside_destroy;
if (!draw_alloc_temp_verts(&twoside->stage, 3))
goto fail;
return &twoside->stage;
fail:
if (twoside)
twoside->stage.destroy(&twoside->stage);
return NULL;
}
@@ -0,0 +1,315 @@
/**************************************************************************
*
* Copyright 2007 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 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 ITS 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.
*
**************************************************************************/
/**
* \brief Drawing stage for handling glPolygonMode(line/point).
* Convert triangles to points or lines as needed.
*/
/* Authors: Keith Whitwell <[email protected]>
*/
#include "util/u_memory.h"
#include "pipe/p_defines.h"
#include "draw_private.h"
#include "draw_pipe.h"
#include "draw_fs.h"
struct unfilled_stage {
struct draw_stage stage;
/** [0] = front face, [1] = back face.
* legal values: PIPE_POLYGON_MODE_FILL, PIPE_POLYGON_MODE_LINE,
* and PIPE_POLYGON_MODE_POINT,
*/
unsigned mode[2];
int face_slot;
};
static inline struct
unfilled_stage *unfilled_stage(struct draw_stage *stage)
{
return (struct unfilled_stage *) stage;
}
static void
inject_front_face_info(struct draw_stage *stage,
struct prim_header *header)
{
struct unfilled_stage *unfilled = unfilled_stage(stage);
bool is_front_face = (
(stage->draw->rasterizer->front_ccw && header->det < 0.0f) ||
(!stage->draw->rasterizer->front_ccw && header->det > 0.0f));
int slot = unfilled->face_slot;
/* In case the backend doesn't care about it */
if (slot < 0) {
return;
}
for (unsigned i = 0; i < 3; ++i) {
struct vertex_header *v = header->v[i];
v->data[slot][0] = is_front_face;
v->data[slot][1] = is_front_face;
v->data[slot][2] = is_front_face;
v->data[slot][3] = is_front_face;
v->vertex_id = UNDEFINED_VERTEX_ID;
}
}
static void
point(struct draw_stage *stage,
struct prim_header *header,
struct vertex_header *v0)
{
struct prim_header tmp;
tmp.det = header->det;
tmp.flags = 0;
tmp.v[0] = v0;
stage->next->point(stage->next, &tmp);
}
static void
line(struct draw_stage *stage,
struct prim_header *header,
struct vertex_header *v0,
struct vertex_header *v1)
{
struct prim_header tmp;
tmp.det = header->det;
tmp.flags = 0;
tmp.v[0] = v0;
tmp.v[1] = v1;
stage->next->line(stage->next, &tmp);
}
static void
points(struct draw_stage *stage,
struct prim_header *header)
{
struct vertex_header *v0 = header->v[0];
struct vertex_header *v1 = header->v[1];
struct vertex_header *v2 = header->v[2];
inject_front_face_info(stage, header);
if ((header->flags & DRAW_PIPE_EDGE_FLAG_0) && v0->edgeflag)
point(stage, header, v0);
if ((header->flags & DRAW_PIPE_EDGE_FLAG_1) && v1->edgeflag)
point(stage, header, v1);
if ((header->flags & DRAW_PIPE_EDGE_FLAG_2) && v2->edgeflag)
point(stage, header, v2);
}
static void
lines(struct draw_stage *stage,
struct prim_header *header)
{
struct vertex_header *v0 = header->v[0];
struct vertex_header *v1 = header->v[1];
struct vertex_header *v2 = header->v[2];
if (header->flags & DRAW_PIPE_RESET_STIPPLE)
/*
* XXX could revisit this. The only stage which cares is the line
* stipple stage. Could just emit correct reset flags here and not
* bother about all the calling through reset_stipple_counter
* stages. Though technically it is necessary if line stipple is
* handled by the driver, but this is not actually hooked up when
* using vbuf (vbuf stage reset_stipple_counter does nothing).
*/
stage->next->reset_stipple_counter(stage->next);
inject_front_face_info(stage, header);
if ((header->flags & DRAW_PIPE_EDGE_FLAG_2) && v2->edgeflag)
line(stage, header, v2, v0);
if ((header->flags & DRAW_PIPE_EDGE_FLAG_0) && v0->edgeflag)
line(stage, header, v0, v1);
if ((header->flags & DRAW_PIPE_EDGE_FLAG_1) && v1->edgeflag)
line(stage, header, v1, v2);
}
/** For debugging */
static void
print_header_flags(unsigned flags)
{
debug_printf("header->flags = ");
if (flags & DRAW_PIPE_RESET_STIPPLE)
debug_printf("RESET_STIPPLE ");
if (flags & DRAW_PIPE_EDGE_FLAG_0)
debug_printf("EDGE_FLAG_0 ");
if (flags & DRAW_PIPE_EDGE_FLAG_1)
debug_printf("EDGE_FLAG_1 ");
if (flags & DRAW_PIPE_EDGE_FLAG_2)
debug_printf("EDGE_FLAG_2 ");
debug_printf("\n");
}
/* Unfilled tri:
*
* Note edgeflags in the vertex struct is not sufficient as we will
* need to manipulate them when decomposing primitives.
*
* We currently keep the vertex edgeflag and primitive edgeflag mask
* separate until the last possible moment.
*/
static void
unfilled_tri(struct draw_stage *stage,
struct prim_header *header)
{
struct unfilled_stage *unfilled = unfilled_stage(stage);
unsigned cw = header->det >= 0.0;
unsigned mode = unfilled->mode[cw];
if (0)
print_header_flags(header->flags);
switch (mode) {
case PIPE_POLYGON_MODE_FILL:
stage->next->tri(stage->next, header);
break;
case PIPE_POLYGON_MODE_LINE:
lines(stage, header);
break;
case PIPE_POLYGON_MODE_POINT:
points(stage, header);
break;
default:
assert(0);
}
}
static void
unfilled_first_tri(struct draw_stage *stage,
struct prim_header *header)
{
struct unfilled_stage *unfilled = unfilled_stage(stage);
const struct pipe_rasterizer_state *rast = stage->draw->rasterizer;
unfilled->mode[0] = rast->front_ccw ? rast->fill_front : rast->fill_back;
unfilled->mode[1] = rast->front_ccw ? rast->fill_back : rast->fill_front;
stage->tri = unfilled_tri;
stage->tri(stage, header);
}
static void
unfilled_flush(struct draw_stage *stage,
unsigned flags)
{
stage->next->flush(stage->next, flags);
stage->tri = unfilled_first_tri;
}
static void
unfilled_reset_stipple_counter(struct draw_stage *stage)
{
stage->next->reset_stipple_counter(stage->next);
}
static void
unfilled_destroy(struct draw_stage *stage)
{
draw_free_temp_verts(stage);
FREE(stage);
}
/*
* Try to allocate an output slot which we can use
* to preserve the front face information.
*/
void
draw_unfilled_prepare_outputs(struct draw_context *draw,
struct draw_stage *stage)
{
struct unfilled_stage *unfilled = unfilled_stage(stage);
const struct pipe_rasterizer_state *rast = draw ? draw->rasterizer : NULL;
bool is_unfilled = (rast &&
(rast->fill_front != PIPE_POLYGON_MODE_FILL ||
rast->fill_back != PIPE_POLYGON_MODE_FILL));
const struct draw_fragment_shader *fs = draw ? draw->fs.fragment_shader : NULL;
if (is_unfilled && fs && fs->info.uses_frontface) {
unfilled->face_slot = draw_alloc_extra_vertex_attrib(
stage->draw, TGSI_SEMANTIC_FACE, 0);
} else {
unfilled->face_slot = -1;
}
}
/**
* Create unfilled triangle stage.
*/
struct draw_stage *
draw_unfilled_stage(struct draw_context *draw)
{
struct unfilled_stage *unfilled = CALLOC_STRUCT(unfilled_stage);
if (!unfilled)
goto fail;
unfilled->stage.draw = draw;
unfilled->stage.name = "unfilled";
unfilled->stage.next = NULL;
unfilled->stage.tmp = NULL;
unfilled->stage.point = draw_pipe_passthrough_point;
unfilled->stage.line = draw_pipe_passthrough_line;
unfilled->stage.tri = unfilled_first_tri;
unfilled->stage.flush = unfilled_flush;
unfilled->stage.reset_stipple_counter = unfilled_reset_stipple_counter;
unfilled->stage.destroy = unfilled_destroy;
unfilled->face_slot = -1;
if (!draw_alloc_temp_verts(&unfilled->stage, 0))
goto fail;
return &unfilled->stage;
fail:
if (unfilled)
unfilled->stage.destroy(&unfilled->stage);
return NULL;
}
@@ -0,0 +1,206 @@
/**************************************************************************
*
* Copyright 2007 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 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 ITS 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.
*
**************************************************************************/
/**
* \brief Drawing stage for user culling
*/
#include "util/u_math.h"
#include "util/u_memory.h"
#include "pipe/p_defines.h"
#include "draw_pipe.h"
struct user_cull_stage {
struct draw_stage stage;
};
static inline bool
cull_distance_is_out(float dist)
{
return (dist < 0.0f) || util_is_inf_or_nan(dist);
}
/*
* If the shader writes the culldistance then we can
* perform distance based culling. Distance based
* culling doesn't require a face and can be performed
* on primitives without faces (e.g. points and lines)
*/
static void
user_cull_point(struct draw_stage *stage,
struct prim_header *header)
{
const unsigned num_written_culldistances =
draw_current_shader_num_written_culldistances(stage->draw);
const unsigned num_written_clipdistances =
draw_current_shader_num_written_clipdistances(stage->draw);
assert(num_written_culldistances);
for (unsigned i = 0; i < num_written_culldistances; ++i) {
unsigned cull_idx = (num_written_clipdistances + i) / 4;
unsigned out_idx =
draw_current_shader_ccdistance_output(stage->draw, cull_idx);
unsigned idx = (num_written_clipdistances + i) % 4;
float cull1 = header->v[0]->data[out_idx][idx];
bool vert1_out = cull_distance_is_out(cull1);
if (vert1_out)
return;
}
stage->next->point(stage->next, header);
}
/*
* If the shader writes the culldistance then we can
* perform distance based culling. Distance based
* culling doesn't require a face and can be performed
* on primitives without faces (e.g. points and lines)
*/
static void
user_cull_line(struct draw_stage *stage,
struct prim_header *header)
{
const unsigned num_written_culldistances =
draw_current_shader_num_written_culldistances(stage->draw);
const unsigned num_written_clipdistances =
draw_current_shader_num_written_clipdistances(stage->draw);
assert(num_written_culldistances);
for (unsigned i = 0; i < num_written_culldistances; ++i) {
unsigned cull_idx = (num_written_clipdistances + i) / 4;
unsigned out_idx =
draw_current_shader_ccdistance_output(stage->draw, cull_idx);
unsigned idx = (num_written_clipdistances + i) % 4;
float cull1 = header->v[0]->data[out_idx][idx];
float cull2 = header->v[1]->data[out_idx][idx];
bool vert1_out = cull_distance_is_out(cull1);
bool vert2_out = cull_distance_is_out(cull2);
if (vert1_out && vert2_out)
return;
}
stage->next->line(stage->next, header);
}
/*
* Triangles can be culled either using the cull distance
* shader outputs or the regular face culling. If required
* this function performs both, starting with distance culling.
*/
static void
user_cull_tri(struct draw_stage *stage,
struct prim_header *header)
{
const unsigned num_written_culldistances =
draw_current_shader_num_written_culldistances(stage->draw);
const unsigned num_written_clipdistances =
draw_current_shader_num_written_clipdistances(stage->draw);
unsigned i;
assert(num_written_culldistances);
/* Do the distance culling */
for (i = 0; i < num_written_culldistances; ++i) {
unsigned cull_idx = (num_written_clipdistances + i) / 4;
unsigned out_idx =
draw_current_shader_ccdistance_output(stage->draw, cull_idx);
unsigned idx = (num_written_clipdistances + i) % 4;
float cull1 = header->v[0]->data[out_idx][idx];
float cull2 = header->v[1]->data[out_idx][idx];
float cull3 = header->v[2]->data[out_idx][idx];
bool vert1_out = cull_distance_is_out(cull1);
bool vert2_out = cull_distance_is_out(cull2);
bool vert3_out = cull_distance_is_out(cull3);
if (vert1_out && vert2_out && vert3_out) {
return;
}
}
stage->next->tri(stage->next, header);
}
static void
user_cull_flush(struct draw_stage *stage, unsigned flags)
{
stage->point = user_cull_point;
stage->line = user_cull_line;
stage->tri = user_cull_tri;
stage->next->flush(stage->next, flags);
}
static void
user_cull_reset_stipple_counter(struct draw_stage *stage)
{
stage->next->reset_stipple_counter(stage->next);
}
static void
user_cull_destroy(struct draw_stage *stage)
{
draw_free_temp_verts(stage);
FREE(stage);
}
/**
* Create a new polygon culling stage.
*/
struct draw_stage *
draw_user_cull_stage(struct draw_context *draw)
{
struct user_cull_stage *user_cull = CALLOC_STRUCT(user_cull_stage);
if (!user_cull)
goto fail;
user_cull->stage.draw = draw;
user_cull->stage.name = "user_cull";
user_cull->stage.next = NULL;
user_cull->stage.point = user_cull_point;
user_cull->stage.line = user_cull_line;
user_cull->stage.tri = user_cull_tri;
user_cull->stage.flush = user_cull_flush;
user_cull->stage.reset_stipple_counter = user_cull_reset_stipple_counter;
user_cull->stage.destroy = user_cull_destroy;
if (!draw_alloc_temp_verts(&user_cull->stage, 0))
goto fail;
return &user_cull->stage;
fail:
if (user_cull)
user_cull->stage.destroy(&user_cull->stage);
return NULL;
}
+132
View File
@@ -0,0 +1,132 @@
/**************************************************************************
*
* Copyright 2007 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 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 ITS 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.
*
**************************************************************************/
/*
* Authors:
* Keith Whitwell <[email protected]>
*/
#include "util/u_memory.h"
#include "draw/draw_private.h"
#include "draw/draw_pipe.h"
void
draw_pipe_passthrough_point(struct draw_stage *stage, struct prim_header *header)
{
stage->next->point(stage->next, header);
}
void
draw_pipe_passthrough_line(struct draw_stage *stage, struct prim_header *header)
{
stage->next->line(stage->next, header);
}
void
draw_pipe_passthrough_tri(struct draw_stage *stage, struct prim_header *header)
{
stage->next->tri(stage->next, header);
}
/* This is only used for temporary verts.
*/
#define MAX_VERTEX_SIZE ((2 + PIPE_MAX_SHADER_OUTPUTS) * 4 * sizeof(float))
/**
* Allocate space for temporary post-transform vertices, such as for clipping.
*/
bool
draw_alloc_temp_verts(struct draw_stage *stage, unsigned nr)
{
assert(!stage->tmp);
stage->tmp = NULL;
stage->nr_tmps = nr;
if (nr != 0) {
uint8_t *store = (uint8_t *) MALLOC(MAX_VERTEX_SIZE * nr +
DRAW_EXTRA_VERTICES_PADDING);
if (!store)
return false;
stage->tmp = (struct vertex_header **) MALLOC(sizeof(struct vertex_header *) * nr);
if (stage->tmp == NULL) {
FREE(store);
return false;
}
for (unsigned i = 0; i < nr; i++)
stage->tmp[i] = (struct vertex_header *)(store + i * MAX_VERTEX_SIZE);
}
return true;
}
void
draw_free_temp_verts(struct draw_stage *stage)
{
if (stage->tmp) {
FREE(stage->tmp[0]);
FREE(stage->tmp);
stage->tmp = NULL;
}
}
/* Reset vertex ids. This is basically a type of flush.
*
* Called only from draw_pipe_vbuf.c
*/
void
draw_reset_vertex_ids(struct draw_context *draw)
{
struct draw_stage *stage = draw->pipeline.first;
while (stage) {
for (unsigned i = 0; i < stage->nr_tmps; i++)
stage->tmp[i]->vertex_id = UNDEFINED_VERTEX_ID;
stage = stage->next;
}
if (draw->pipeline.verts) {
char *verts = draw->pipeline.verts;
unsigned stride = draw->pipeline.vertex_stride;
for (unsigned i = 0; i < draw->pipeline.vertex_count; i++) {
((struct vertex_header *)verts)->vertex_id = UNDEFINED_VERTEX_ID;
verts += stride;
}
}
}
@@ -0,0 +1,357 @@
/**************************************************************************
*
* Copyright 2007 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 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 ITS 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.
*
**************************************************************************/
/* Authors: Keith Whitwell <[email protected]>
*/
#include "util/u_memory.h"
#include "util/u_math.h"
#include "util/u_prim.h"
#include "pipe/p_defines.h"
#include "draw_private.h"
#include "draw_pipe.h"
#include "draw_context.h"
#include "draw_vbuf.h"
/**
* Default version of a function to check if we need any special
* pipeline stages, or whether prims/verts can go through untouched.
* Don't test for bypass clipping or vs modes, this function is just
* about the primitive pipeline stages.
*
* This can be overridden by the driver.
*/
bool
draw_need_pipeline(const struct draw_context *draw,
const struct pipe_rasterizer_state *rasterizer,
enum mesa_prim prim)
{
unsigned reduced_prim = u_reduced_prim(prim);
/* If the driver has overridden this, use that version:
*/
if (draw->render && draw->render->need_pipeline) {
return draw->render->need_pipeline(draw->render, rasterizer, prim);
}
/* Don't have to worry about triangles turning into lines/points
* and triggering the pipeline, because we have to trigger the
* pipeline *anyway* if unfilled mode is active.
*/
if (reduced_prim == MESA_PRIM_LINES) {
/* line stipple */
if (rasterizer->line_stipple_enable && draw->pipeline.line_stipple)
return true;
/* wide lines */
if (roundf(rasterizer->line_width) > draw->pipeline.wide_line_threshold)
return true;
/* AA lines */
if ((!rasterizer->multisample && rasterizer->line_smooth) && draw->pipeline.aaline)
return true;
if (draw_current_shader_num_written_culldistances(draw))
return true;
} else if (reduced_prim == MESA_PRIM_POINTS) {
/* large points */
if (rasterizer->point_size > draw->pipeline.wide_point_threshold)
return true;
/* sprite points */
if (rasterizer->point_quad_rasterization
&& draw->pipeline.wide_point_sprites)
return true;
/* AA points */
if ((!rasterizer->multisample && rasterizer->point_smooth) && draw->pipeline.aapoint)
return true;
/* point sprites */
if (rasterizer->sprite_coord_enable && draw->pipeline.point_sprite)
return true;
if (draw_current_shader_num_written_culldistances(draw))
return true;
} else if (reduced_prim == MESA_PRIM_TRIANGLES) {
/* polygon stipple */
if (rasterizer->poly_stipple_enable && draw->pipeline.pstipple)
return true;
/* unfilled polygons */
if (rasterizer->fill_front != PIPE_POLYGON_MODE_FILL ||
rasterizer->fill_back != PIPE_POLYGON_MODE_FILL)
return true;
/* polygon offset */
if (rasterizer->offset_point ||
rasterizer->offset_line ||
rasterizer->offset_tri)
return true;
/* two-side lighting */
if (rasterizer->light_twoside)
return true;
if (draw_current_shader_num_written_culldistances(draw))
return true;
}
/* polygon cull - this is difficult - hardware can cull just fine
* most of the time (though sometimes CULL_NEITHER is unsupported.
*
* Generally this isn't a reason to require the pipeline, though.
*
if (rasterizer->cull_mode)
return TRUE;
*/
return false;
}
/**
* Rebuild the rendering pipeline.
*/
static struct draw_stage *
validate_pipeline(struct draw_stage *stage)
{
struct draw_context *draw = stage->draw;
struct draw_stage *next = draw->pipeline.rasterize;
bool need_det = false;
bool precalc_flat = false;
bool wide_lines, wide_points;
const struct pipe_rasterizer_state *rast = draw->rasterizer;
/* Set the validate's next stage to the rasterize stage, so that it
* can be found later if needed for flushing.
*/
stage->next = next;
/* drawing wide, non-AA lines? */
wide_lines = rast->line_width != 1.0f &&
roundf(rast->line_width) > draw->pipeline.wide_line_threshold &&
(!rast->line_smooth || rast->multisample);
/* drawing large/sprite points (but not AA points)? */
if (rast->sprite_coord_enable && draw->pipeline.point_sprite)
wide_points = true;
else if ((!rast->multisample && rast->point_smooth) && draw->pipeline.aapoint)
wide_points = false;
else if (rast->point_size > draw->pipeline.wide_point_threshold)
wide_points = true;
else if (rast->point_quad_rasterization && draw->pipeline.wide_point_sprites)
wide_points = true;
else
wide_points = false;
/*
* NOTE: we build up the pipeline in end-to-start order.
*
* TODO: make the current primitive part of the state and build
* shorter pipelines for lines & points.
*/
if ((!rast->multisample && rast->line_smooth) && draw->pipeline.aaline) {
draw->pipeline.aaline->next = next;
next = draw->pipeline.aaline;
precalc_flat = true;
}
if ((!rast->multisample && rast->point_smooth) && draw->pipeline.aapoint) {
draw->pipeline.aapoint->next = next;
next = draw->pipeline.aapoint;
}
if (wide_lines) {
draw->pipeline.wide_line->next = next;
next = draw->pipeline.wide_line;
precalc_flat = true;
}
if (wide_points) {
draw->pipeline.wide_point->next = next;
next = draw->pipeline.wide_point;
}
if (rast->line_stipple_enable && draw->pipeline.line_stipple) {
draw->pipeline.stipple->next = next;
next = draw->pipeline.stipple;
precalc_flat = true; /* only needed for lines really */
}
if (rast->poly_stipple_enable
&& draw->pipeline.pstipple) {
draw->pipeline.pstipple->next = next;
next = draw->pipeline.pstipple;
}
if (rast->fill_front != PIPE_POLYGON_MODE_FILL ||
rast->fill_back != PIPE_POLYGON_MODE_FILL) {
draw->pipeline.unfilled->next = next;
next = draw->pipeline.unfilled;
precalc_flat = true; /* only needed for triangles really */
need_det = true;
}
if (precalc_flat) {
/*
* could only run the stage if either rast->flatshade is true
* or there's constant interpolated values.
*/
draw->pipeline.flatshade->next = next;
next = draw->pipeline.flatshade;
}
if (rast->offset_point ||
rast->offset_line ||
rast->offset_tri) {
draw->pipeline.offset->next = next;
next = draw->pipeline.offset;
need_det = true;
}
if (rast->light_twoside) {
draw->pipeline.twoside->next = next;
next = draw->pipeline.twoside;
need_det = true;
}
/* Always run the cull stage as we calculate determinant there
* also.
*
* This can actually be a win as culling out the triangles can lead
* to less work emitting vertices, smaller vertex buffers, etc.
* It's difficult to say whether this will be true in general.
*/
if (need_det || rast->cull_face != PIPE_FACE_NONE) {
draw->pipeline.cull->next = next;
next = draw->pipeline.cull;
}
/* Clip stage
*/
if (draw->clip_xy || draw->clip_z || draw->clip_user) {
draw->pipeline.clip->next = next;
next = draw->pipeline.clip;
}
if (draw_current_shader_num_written_culldistances(draw)) {
draw->pipeline.user_cull->next = next;
next = draw->pipeline.user_cull;
}
draw->pipeline.first = next;
if (0) {
debug_printf("draw pipeline:\n");
for (next = draw->pipeline.first; next ; next = next->next)
debug_printf(" %s\n", next->name);
debug_printf("\n");
}
return draw->pipeline.first;
}
static void
validate_tri(struct draw_stage *stage,
struct prim_header *header)
{
struct draw_stage *pipeline = validate_pipeline(stage);
pipeline->tri(pipeline, header);
}
static void
validate_line(struct draw_stage *stage,
struct prim_header *header)
{
struct draw_stage *pipeline = validate_pipeline(stage);
pipeline->line(pipeline, header);
}
static void
validate_point(struct draw_stage *stage,
struct prim_header *header)
{
struct draw_stage *pipeline = validate_pipeline(stage);
pipeline->point(pipeline, header);
}
static void
validate_reset_stipple_counter(struct draw_stage *stage)
{
struct draw_stage *pipeline = validate_pipeline(stage);
pipeline->reset_stipple_counter(pipeline);
}
static void
validate_flush(struct draw_stage *stage,
unsigned flags)
{
/* May need to pass a backend flush on to the rasterize stage.
*/
if (stage->next)
stage->next->flush(stage->next, flags);
}
static void
validate_destroy(struct draw_stage *stage)
{
FREE(stage);
}
/**
* Create validate pipeline stage.
*/
struct draw_stage *
draw_validate_stage(struct draw_context *draw)
{
struct draw_stage *stage = CALLOC_STRUCT(draw_stage);
if (!stage)
return NULL;
stage->draw = draw;
stage->name = "validate";
stage->next = NULL;
stage->point = validate_point;
stage->line = validate_line;
stage->tri = validate_tri;
stage->flush = validate_flush;
stage->reset_stipple_counter = validate_reset_stipple_counter;
stage->destroy = validate_destroy;
return stage;
}
+452
View File
@@ -0,0 +1,452 @@
/**************************************************************************
*
* Copyright 2007 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 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 ITS 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.
*
**************************************************************************/
/**
* \file
* Vertex buffer drawing stage.
*
* \author Jose Fonseca <[email protected]>
* \author Keith Whitwell <[email protected]>
*/
#include "util/u_debug.h"
#include "util/u_math.h"
#include "util/u_memory.h"
#include "draw_vbuf.h"
#include "draw_private.h"
#include "draw_vertex.h"
#include "draw_pipe.h"
#include "translate/translate.h"
#include "translate/translate_cache.h"
/**
* Vertex buffer emit stage.
*/
struct vbuf_stage {
struct draw_stage stage; /**< This must be first (base class) */
struct vbuf_render *render;
const struct vertex_info *vinfo;
/** Vertex size in bytes */
unsigned vertex_size;
struct translate *translate;
/* FIXME: we have no guarantee that 'unsigned' is 32bit */
/** Vertices in hardware format */
uint8_t *vertices;
uint8_t *vertex_ptr;
unsigned max_vertices;
unsigned nr_vertices;
/** Indices */
uint16_t *indices;
unsigned max_indices;
unsigned nr_indices;
/* Cache point size somewhere its address won't change:
*/
float point_size;
float zero4[4];
struct translate_cache *cache;
};
/**
* Basically a cast wrapper.
*/
static inline struct vbuf_stage *
vbuf_stage(struct draw_stage *stage)
{
assert(stage);
return (struct vbuf_stage *)stage;
}
static void vbuf_flush_vertices(struct vbuf_stage *vbuf);
static void vbuf_alloc_vertices(struct vbuf_stage *vbuf);
static inline void
check_space(struct vbuf_stage *vbuf, unsigned nr)
{
if (vbuf->nr_vertices + nr > vbuf->max_vertices ||
vbuf->nr_indices + nr > vbuf->max_indices) {
vbuf_flush_vertices(vbuf);
vbuf_alloc_vertices(vbuf);
}
}
/**
* Extract the needed fields from post-transformed vertex and emit
* a hardware(driver) vertex.
* Recall that the vertices are constructed by the 'draw' module and
* have a couple of slots at the beginning (1-dword header, 4-dword
* clip pos) that we ignore here. We only use the vertex->data[] fields.
*/
static inline uint16_t
emit_vertex(struct vbuf_stage *vbuf, struct vertex_header *vertex)
{
if (vertex->vertex_id == UNDEFINED_VERTEX_ID && vbuf->vertex_ptr) {
/* Hmm - vertices are emitted one at a time - better make sure
* set_buffer is efficient. Consider a special one-shot mode for
* translate.
*/
/* Note: we really do want data[0] here, not data[pos]:
*/
vbuf->translate->set_buffer(vbuf->translate, 0, vertex->data[0], 0, ~0);
vbuf->translate->run(vbuf->translate, 0, 1, 0, 0, vbuf->vertex_ptr);
if (0) draw_dump_emitted_vertex(vbuf->vinfo, (uint8_t *)vbuf->vertex_ptr);
vbuf->vertex_ptr += vbuf->vertex_size;
vertex->vertex_id = vbuf->nr_vertices++;
}
return (uint16_t)vertex->vertex_id;
}
static void
vbuf_tri(struct draw_stage *stage, struct prim_header *prim)
{
struct vbuf_stage *vbuf = vbuf_stage(stage);
unsigned i;
check_space(vbuf, 3);
for (i = 0; i < 3; i++) {
vbuf->indices[vbuf->nr_indices++] = emit_vertex(vbuf, prim->v[i]);
}
}
static void
vbuf_line(struct draw_stage *stage, struct prim_header *prim)
{
struct vbuf_stage *vbuf = vbuf_stage(stage);
unsigned i;
check_space(vbuf, 2);
for (i = 0; i < 2; i++) {
vbuf->indices[vbuf->nr_indices++] = emit_vertex(vbuf, prim->v[i]);
}
}
static void
vbuf_point(struct draw_stage *stage, struct prim_header *prim)
{
struct vbuf_stage *vbuf = vbuf_stage(stage);
check_space(vbuf, 1);
vbuf->indices[vbuf->nr_indices++] = emit_vertex(vbuf, prim->v[0]);
}
/**
* Set the prim type for subsequent vertices.
* This may result in a new vertex size. The existing vbuffer (if any)
* will be flushed if needed and a new one allocated.
*/
static void
vbuf_start_prim(struct vbuf_stage *vbuf, enum mesa_prim prim)
{
struct translate_key hw_key;
unsigned dst_offset;
unsigned i;
const struct vertex_info *vinfo;
vbuf->render->set_primitive(vbuf->render, prim);
if (vbuf->render->set_view_index)
vbuf->render->set_view_index(vbuf->render, vbuf->stage.draw->pt.user.viewid);
/* Must do this after set_primitive() above:
*
* XXX: need some state managment to track when this needs to be
* recalculated. The driver should tell us whether there was a
* state change.
*/
vbuf->vinfo = vbuf->render->get_vertex_info(vbuf->render);
vinfo = vbuf->vinfo;
vbuf->vertex_size = vinfo->size * sizeof(float);
/* Translate from pipeline vertices to hw vertices.
*/
dst_offset = 0;
for (i = 0; i < vinfo->num_attribs; i++) {
unsigned emit_sz = 0;
unsigned src_buffer = 0;
enum pipe_format output_format;
unsigned src_offset = (vinfo->attrib[i].src_index * 4 * sizeof(float));
output_format = draw_translate_vinfo_format(vinfo->attrib[i].emit);
emit_sz = draw_translate_vinfo_size(vinfo->attrib[i].emit);
/* doesn't handle EMIT_OMIT */
assert(emit_sz != 0);
if (vinfo->attrib[i].emit == EMIT_1F_PSIZE) {
src_buffer = 1;
src_offset = 0;
}
else if (vinfo->attrib[i].src_index == DRAW_ATTR_NONEXIST) {
/* elements which don't exist will get assigned zeros */
src_buffer = 2;
src_offset = 0;
}
hw_key.element[i].type = TRANSLATE_ELEMENT_NORMAL;
hw_key.element[i].input_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
hw_key.element[i].input_buffer = src_buffer;
hw_key.element[i].input_offset = src_offset;
hw_key.element[i].instance_divisor = 0;
hw_key.element[i].output_format = output_format;
hw_key.element[i].output_offset = dst_offset;
dst_offset += emit_sz;
}
hw_key.nr_elements = vinfo->num_attribs;
hw_key.output_stride = vbuf->vertex_size;
/* Don't bother with caching at this stage:
*/
if (!vbuf->translate ||
translate_key_compare(&vbuf->translate->key, &hw_key) != 0) {
translate_key_sanitize(&hw_key);
vbuf->translate = translate_cache_find(vbuf->cache, &hw_key);
vbuf->translate->set_buffer(vbuf->translate, 1, &vbuf->point_size, 0, ~0);
vbuf->translate->set_buffer(vbuf->translate, 2, &vbuf->zero4[0], 0, ~0);
}
vbuf->point_size = vbuf->stage.draw->rasterizer->point_size;
/* Allocate new buffer?
*/
assert(vbuf->vertices == NULL);
vbuf_alloc_vertices(vbuf);
}
static void
vbuf_first_tri(struct draw_stage *stage, struct prim_header *prim)
{
struct vbuf_stage *vbuf = vbuf_stage(stage);
vbuf_flush_vertices(vbuf);
vbuf_start_prim(vbuf, MESA_PRIM_TRIANGLES);
stage->tri = vbuf_tri;
stage->tri(stage, prim);
}
static void
vbuf_first_line(struct draw_stage *stage, struct prim_header *prim)
{
struct vbuf_stage *vbuf = vbuf_stage(stage);
vbuf_flush_vertices(vbuf);
vbuf_start_prim(vbuf, MESA_PRIM_LINES);
stage->line = vbuf_line;
stage->line(stage, prim);
}
static void
vbuf_first_point(struct draw_stage *stage, struct prim_header *prim)
{
struct vbuf_stage *vbuf = vbuf_stage(stage);
vbuf_flush_vertices(vbuf);
vbuf_start_prim(vbuf, MESA_PRIM_POINTS);
stage->point = vbuf_point;
stage->point(stage, prim);
}
/**
* Flush existing vertex buffer and allocate a new one.
*/
static void
vbuf_flush_vertices(struct vbuf_stage *vbuf)
{
if (vbuf->vertices) {
vbuf->render->unmap_vertices(vbuf->render, 0, vbuf->nr_vertices - 1);
if (vbuf->nr_indices) {
vbuf->render->draw_elements(vbuf->render,
vbuf->indices,
vbuf->nr_indices);
vbuf->nr_indices = 0;
}
/* Reset temporary vertices ids */
if (vbuf->nr_vertices)
draw_reset_vertex_ids(vbuf->stage.draw);
/* Free the vertex buffer */
vbuf->render->release_vertices(vbuf->render);
vbuf->max_vertices = vbuf->nr_vertices = 0;
vbuf->vertex_ptr = vbuf->vertices = NULL;
}
/* Reset point/line/tri function pointers.
* If (for example) we transition from points to tris and back to points
* again, we need to call the vbuf_first_point() function again to flush
* the triangles before drawing more points. This can happen when drawing
* with front polygon mode = filled and back polygon mode = line or point.
*/
vbuf->stage.point = vbuf_first_point;
vbuf->stage.line = vbuf_first_line;
vbuf->stage.tri = vbuf_first_tri;
}
static void
vbuf_alloc_vertices(struct vbuf_stage *vbuf)
{
if (vbuf->vertex_ptr) {
assert(!vbuf->nr_indices);
assert(!vbuf->vertices);
}
/* Allocate a new vertex buffer */
vbuf->max_vertices =
vbuf->render->max_vertex_buffer_bytes / vbuf->vertex_size;
if (vbuf->max_vertices >= UNDEFINED_VERTEX_ID)
vbuf->max_vertices = UNDEFINED_VERTEX_ID - 1;
/* Must always succeed -- driver gives us a
* 'max_vertex_buffer_bytes' which it guarantees it can allocate,
* and it will flush itself if necessary to do so. If this does
* fail, we are basically without usable hardware.
*/
vbuf->render->allocate_vertices(vbuf->render,
(uint16_t) vbuf->vertex_size,
(uint16_t) vbuf->max_vertices);
vbuf->vertex_ptr = vbuf->vertices =
vbuf->render->map_vertices(vbuf->render);
}
static void
vbuf_flush(struct draw_stage *stage, unsigned flags)
{
struct vbuf_stage *vbuf = vbuf_stage(stage);
vbuf_flush_vertices(vbuf);
}
static void
vbuf_reset_stipple_counter(struct draw_stage *stage)
{
/* XXX: Need to do something here for hardware with linestipple.
*/
(void) stage;
}
static void
vbuf_destroy(struct draw_stage *stage)
{
struct vbuf_stage *vbuf = vbuf_stage(stage);
if (vbuf->indices)
align_free(vbuf->indices);
if (vbuf->render)
vbuf->render->destroy(vbuf->render);
if (vbuf->cache)
translate_cache_destroy(vbuf->cache);
FREE(stage);
}
/**
* Create a new primitive vbuf/render stage.
*/
struct draw_stage *
draw_vbuf_stage(struct draw_context *draw, struct vbuf_render *render)
{
struct vbuf_stage *vbuf = CALLOC_STRUCT(vbuf_stage);
if (!vbuf)
goto fail;
vbuf->stage.draw = draw;
vbuf->stage.name = "vbuf";
vbuf->stage.point = vbuf_first_point;
vbuf->stage.line = vbuf_first_line;
vbuf->stage.tri = vbuf_first_tri;
vbuf->stage.flush = vbuf_flush;
vbuf->stage.reset_stipple_counter = vbuf_reset_stipple_counter;
vbuf->stage.destroy = vbuf_destroy;
vbuf->render = render;
vbuf->max_indices = MIN2(render->max_indices, UNDEFINED_VERTEX_ID-1);
vbuf->indices = (uint16_t *) align_malloc(vbuf->max_indices *
sizeof(vbuf->indices[0]),
16);
if (!vbuf->indices)
goto fail;
vbuf->cache = translate_cache_create();
if (!vbuf->cache)
goto fail;
vbuf->vertex_ptr = vbuf->vertices = NULL;
vbuf->zero4[0] = vbuf->zero4[1] = vbuf->zero4[2] = vbuf->zero4[3] = 0.0f;
return &vbuf->stage;
fail:
if (vbuf)
vbuf_destroy(&vbuf->stage);
return NULL;
}
@@ -0,0 +1,220 @@
/**************************************************************************
*
* Copyright 2007 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 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 ITS 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.
*
**************************************************************************/
/* Authors: Keith Whitwell <[email protected]>
*/
#include "pipe/p_context.h"
#include "pipe/p_defines.h"
#include "pipe/p_shader_tokens.h"
#include "util/u_math.h"
#include "util/u_memory.h"
#include "draw_private.h"
#include "draw_pipe.h"
struct wideline_stage {
struct draw_stage stage;
};
/**
* Draw a wide line by drawing a quad (two triangles).
*/
static void
wideline_line(struct draw_stage *stage,
struct prim_header *header)
{
const unsigned pos = draw_current_shader_position_output(stage->draw);
const float half_width = 0.5f * stage->draw->rasterizer->line_width;
struct prim_header tri;
struct vertex_header *v0 = dup_vert(stage, header->v[0], 0);
struct vertex_header *v1 = dup_vert(stage, header->v[0], 1);
struct vertex_header *v2 = dup_vert(stage, header->v[1], 2);
struct vertex_header *v3 = dup_vert(stage, header->v[1], 3);
float *pos0 = v0->data[pos];
float *pos1 = v1->data[pos];
float *pos2 = v2->data[pos];
float *pos3 = v3->data[pos];
const float dx = fabsf(pos0[0] - pos2[0]);
const float dy = fabsf(pos0[1] - pos2[1]);
const bool half_pixel_center =
stage->draw->rasterizer->half_pixel_center;
/* small tweak to meet GL specification */
const float bias = half_pixel_center ? 0.125f : 0.0f;
/*
* Draw wide line as a quad (two tris) by "stretching" the line along
* X or Y.
* We need to tweak coords in several ways to be conformant here.
*/
if (dx > dy) {
/* x-major line */
pos0[1] = pos0[1] - half_width - bias;
pos1[1] = pos1[1] + half_width - bias;
pos2[1] = pos2[1] - half_width - bias;
pos3[1] = pos3[1] + half_width - bias;
if (half_pixel_center) {
if (pos0[0] < pos2[0]) {
/* left to right line */
pos0[0] -= 0.5f;
pos1[0] -= 0.5f;
pos2[0] -= 0.5f;
pos3[0] -= 0.5f;
} else {
/* right to left line */
pos0[0] += 0.5f;
pos1[0] += 0.5f;
pos2[0] += 0.5f;
pos3[0] += 0.5f;
}
}
} else {
/* y-major line */
pos0[0] = pos0[0] - half_width + bias;
pos1[0] = pos1[0] + half_width + bias;
pos2[0] = pos2[0] - half_width + bias;
pos3[0] = pos3[0] + half_width + bias;
if (half_pixel_center) {
if (pos0[1] < pos2[1]) {
/* top to bottom line */
pos0[1] -= 0.5f;
pos1[1] -= 0.5f;
pos2[1] -= 0.5f;
pos3[1] -= 0.5f;
} else {
/* bottom to top line */
pos0[1] += 0.5f;
pos1[1] += 0.5f;
pos2[1] += 0.5f;
pos3[1] += 0.5f;
}
}
}
tri.det = header->det; /* only the sign matters */
tri.v[0] = v0;
tri.v[1] = v2;
tri.v[2] = v3;
stage->next->tri(stage->next, &tri);
tri.v[0] = v0;
tri.v[1] = v3;
tri.v[2] = v1;
stage->next->tri(stage->next, &tri);
}
static void
wideline_first_line(struct draw_stage *stage,
struct prim_header *header)
{
struct draw_context *draw = stage->draw;
struct pipe_context *pipe = draw->pipe;
const struct pipe_rasterizer_state *rast = draw->rasterizer;
void *r;
/* Disable triangle culling, stippling, unfilled mode etc. */
r = draw_get_rasterizer_no_cull(draw, rast);
draw->suspend_flushing = true;
pipe->bind_rasterizer_state(pipe, r);
draw->suspend_flushing = false;
stage->line = wideline_line;
wideline_line(stage, header);
}
static void
wideline_flush(struct draw_stage *stage, unsigned flags)
{
struct draw_context *draw = stage->draw;
struct pipe_context *pipe = draw->pipe;
stage->line = wideline_first_line;
stage->next->flush(stage->next, flags);
/* restore original rasterizer state */
if (draw->rast_handle) {
draw->suspend_flushing = true;
pipe->bind_rasterizer_state(pipe, draw->rast_handle);
draw->suspend_flushing = false;
}
}
static void
wideline_reset_stipple_counter(struct draw_stage *stage)
{
stage->next->reset_stipple_counter(stage->next);
}
static void
wideline_destroy(struct draw_stage *stage)
{
draw_free_temp_verts(stage);
FREE(stage);
}
struct draw_stage *
draw_wide_line_stage(struct draw_context *draw)
{
struct wideline_stage *wide = CALLOC_STRUCT(wideline_stage);
if (!wide)
goto fail;
wide->stage.draw = draw;
wide->stage.name = "wide-line";
wide->stage.next = NULL;
wide->stage.point = draw_pipe_passthrough_point;
wide->stage.line = wideline_first_line;
wide->stage.tri = draw_pipe_passthrough_tri;
wide->stage.flush = wideline_flush;
wide->stage.reset_stipple_counter = wideline_reset_stipple_counter;
wide->stage.destroy = wideline_destroy;
if (!draw_alloc_temp_verts(&wide->stage, 4))
goto fail;
return &wide->stage;
fail:
if (wide)
wide->stage.destroy(&wide->stage);
return NULL;
}
@@ -0,0 +1,342 @@
/**************************************************************************
*
* Copyright 2007 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 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 ITS 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.
*
**************************************************************************/
/* Authors: Keith Whitwell <[email protected]>
*/
/**
* Notes on wide points and sprite mode:
*
* In wide point/sprite mode we effectively need to convert each incoming
* vertex into four outgoing vertices specifying the corners of a quad.
* Since we don't (yet) have geometry shaders, we have to handle this here
* in the draw module.
*
* For sprites, it also means that this is where we have to handle texcoords
* for the vertices of the quad. OpenGL's GL_COORD_REPLACE state specifies
* if/how enabled texcoords are automatically generated for sprites. We pass
* that info through gallium in the pipe_rasterizer_state::sprite_coord_mode
* array.
*
* Additionally, GLSL's gl_PointCoord fragment attribute has to be handled
* here as well. This is basically an additional texture/generic attribute
* that varies .x from 0 to 1 horizontally across the point and varies .y
* vertically from 0 to 1 down the sprite.
*
* With geometry shaders, the gallium frontends could create a GS to do
* most/all of this.
*/
#include "pipe/p_screen.h"
#include "pipe/p_context.h"
#include "util/u_math.h"
#include "util/u_memory.h"
#include "pipe/p_defines.h"
#include "pipe/p_shader_tokens.h"
#include "draw_fs.h"
#include "draw_vs.h"
#include "draw_pipe.h"
struct widepoint_stage {
struct draw_stage stage; /**< base class */
float half_point_size;
float xbias;
float ybias;
/** for automatic texcoord generation/replacement */
unsigned num_texcoord_gen;
unsigned texcoord_gen_slot[PIPE_MAX_SHADER_OUTPUTS];
/* TGSI_SEMANTIC to which sprite_coord_enable applies */
enum tgsi_semantic sprite_coord_semantic;
int psize_slot;
};
static inline struct widepoint_stage *
widepoint_stage(struct draw_stage *stage)
{
return (struct widepoint_stage *)stage;
}
/**
* Set the vertex texcoords for sprite mode.
* Coords may be left untouched or set to a right-side-up or upside-down
* orientation.
*/
static void
set_texcoords(const struct widepoint_stage *wide,
struct vertex_header *v, const float tc[4])
{
const struct draw_context *draw = wide->stage.draw;
const struct pipe_rasterizer_state *rast = draw->rasterizer;
const unsigned texcoord_mode = rast->sprite_coord_mode;
for (unsigned i = 0; i < wide->num_texcoord_gen; i++) {
const unsigned slot = wide->texcoord_gen_slot[i];
v->data[slot][0] = tc[0];
if (texcoord_mode == PIPE_SPRITE_COORD_LOWER_LEFT)
v->data[slot][1] = 1.0f - tc[1];
else
v->data[slot][1] = tc[1];
v->data[slot][2] = tc[2];
v->data[slot][3] = tc[3];
}
}
/* If there are lots of sprite points (and why wouldn't there be?) it
* would probably be more sensible to change hardware setup to
* optimize this rather than doing the whole thing in software like
* this.
*/
static void
widepoint_point(struct draw_stage *stage,
struct prim_header *header)
{
const struct widepoint_stage *wide = widepoint_stage(stage);
const unsigned pos = draw_current_shader_position_output(stage->draw);
const bool sprite = (bool) stage->draw->rasterizer->point_quad_rasterization;
float half_size;
float left_adj, right_adj, bot_adj, top_adj;
struct prim_header tri;
/* four dups of original vertex */
struct vertex_header *v0 = dup_vert(stage, header->v[0], 0);
struct vertex_header *v1 = dup_vert(stage, header->v[0], 1);
struct vertex_header *v2 = dup_vert(stage, header->v[0], 2);
struct vertex_header *v3 = dup_vert(stage, header->v[0], 3);
float *pos0 = v0->data[pos];
float *pos1 = v1->data[pos];
float *pos2 = v2->data[pos];
float *pos3 = v3->data[pos];
/* point size is either per-vertex or fixed size */
if (wide->psize_slot >= 0) {
half_size = header->v[0]->data[wide->psize_slot][0];
half_size *= 0.5f;
}
else {
half_size = wide->half_point_size;
}
left_adj = -half_size + wide->xbias;
right_adj = half_size + wide->xbias;
bot_adj = half_size + wide->ybias;
top_adj = -half_size + wide->ybias;
pos0[0] += left_adj;
pos0[1] += top_adj;
pos1[0] += left_adj;
pos1[1] += bot_adj;
pos2[0] += right_adj;
pos2[1] += top_adj;
pos3[0] += right_adj;
pos3[1] += bot_adj;
if (sprite) {
static const float tex00[4] = { 0, 0, 0, 1 };
static const float tex01[4] = { 0, 1, 0, 1 };
static const float tex11[4] = { 1, 1, 0, 1 };
static const float tex10[4] = { 1, 0, 0, 1 };
set_texcoords(wide, v0, tex00);
set_texcoords(wide, v1, tex01);
set_texcoords(wide, v2, tex10);
set_texcoords(wide, v3, tex11);
}
tri.det = header->det; /* only the sign matters */
tri.v[0] = v0;
tri.v[1] = v2;
tri.v[2] = v3;
stage->next->tri(stage->next, &tri);
tri.v[0] = v0;
tri.v[1] = v3;
tri.v[2] = v1;
stage->next->tri(stage->next, &tri);
}
static void
widepoint_first_point(struct draw_stage *stage,
struct prim_header *header)
{
struct widepoint_stage *wide = widepoint_stage(stage);
struct draw_context *draw = stage->draw;
struct pipe_context *pipe = draw->pipe;
const struct pipe_rasterizer_state *rast = draw->rasterizer;
void *r;
wide->half_point_size = 0.5f * rast->point_size;
wide->xbias = 0.0;
wide->ybias = 0.0;
if (rast->half_pixel_center) {
wide->xbias = 0.125;
wide->ybias = -0.125;
}
/* Disable triangle culling, stippling, unfilled mode etc. */
r = draw_get_rasterizer_no_cull(draw, rast);
draw->suspend_flushing = true;
pipe->bind_rasterizer_state(pipe, r);
draw->suspend_flushing = false;
/* XXX we won't know the real size if it's computed by the vertex shader! */
if ((rast->point_size > draw->pipeline.wide_point_threshold) ||
(rast->point_quad_rasterization && draw->pipeline.point_sprite)) {
stage->point = widepoint_point;
}
else {
stage->point = draw_pipe_passthrough_point;
}
draw_remove_extra_vertex_attribs(draw);
if (rast->point_quad_rasterization) {
const struct draw_fragment_shader *fs = draw->fs.fragment_shader;
assert(fs);
wide->num_texcoord_gen = 0;
/* Loop over fragment shader inputs looking for the PCOORD input or inputs
* for which bit 'k' in sprite_coord_enable is set.
*/
for (unsigned i = 0; i < fs->info.num_inputs; i++) {
int slot;
const enum tgsi_semantic sn = fs->info.input_semantic_name[i];
const unsigned si = fs->info.input_semantic_index[i];
if (sn == wide->sprite_coord_semantic) {
/* Note that sprite_coord_enable is a bitfield of 32 bits. */
if (si >= 32 || !(rast->sprite_coord_enable & (1 << si)))
continue;
} else if (sn != TGSI_SEMANTIC_PCOORD) {
continue;
}
/* OK, this generic attribute needs to be replaced with a
* sprite coord (see above).
*/
slot = draw_alloc_extra_vertex_attrib(draw, sn, si);
/* add this slot to the texcoord-gen list */
wide->texcoord_gen_slot[wide->num_texcoord_gen++] = slot;
}
}
wide->psize_slot = -1;
if (rast->point_size_per_vertex) {
/* find PSIZ vertex output */
wide->psize_slot = draw_find_shader_output(draw, TGSI_SEMANTIC_PSIZE, 0);
}
stage->point(stage, header);
}
static void
widepoint_flush(struct draw_stage *stage, unsigned flags)
{
struct draw_context *draw = stage->draw;
struct pipe_context *pipe = draw->pipe;
stage->point = widepoint_first_point;
stage->next->flush(stage->next, flags);
draw_remove_extra_vertex_attribs(draw);
/* restore original rasterizer state */
if (draw->rast_handle) {
draw->suspend_flushing = true;
pipe->bind_rasterizer_state(pipe, draw->rast_handle);
draw->suspend_flushing = false;
}
}
static void
widepoint_reset_stipple_counter(struct draw_stage *stage)
{
stage->next->reset_stipple_counter(stage->next);
}
static void
widepoint_destroy(struct draw_stage *stage)
{
draw_free_temp_verts(stage);
FREE(stage);
}
struct draw_stage *draw_wide_point_stage(struct draw_context *draw)
{
struct widepoint_stage *wide = CALLOC_STRUCT(widepoint_stage);
if (!wide)
goto fail;
wide->stage.draw = draw;
wide->stage.name = "wide-point";
wide->stage.next = NULL;
wide->stage.point = widepoint_first_point;
wide->stage.line = draw_pipe_passthrough_line;
wide->stage.tri = draw_pipe_passthrough_tri;
wide->stage.flush = widepoint_flush;
wide->stage.reset_stipple_counter = widepoint_reset_stipple_counter;
wide->stage.destroy = widepoint_destroy;
if (!draw_alloc_temp_verts(&wide->stage, 4))
goto fail;
wide->sprite_coord_semantic =
draw->pipe->screen->caps.tgsi_texcoord
?
TGSI_SEMANTIC_TEXCOORD : TGSI_SEMANTIC_GENERIC;
return &wide->stage;
fail:
if (wide)
wide->stage.destroy(&wide->stage);
return NULL;
}
@@ -0,0 +1,346 @@
/**************************************************************************
*
* Copyright 2013 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 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 ITS 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 "draw_prim_assembler.h"
#include "draw_fs.h"
#include "draw_gs.h"
#include "draw_tess.h"
#include "util/u_debug.h"
#include "util/u_memory.h"
#include "util/u_prim.h"
#include "pipe/p_defines.h"
struct draw_assembler
{
struct draw_context *draw;
struct draw_prim_info *output_prims;
struct draw_vertex_info *output_verts;
const struct draw_prim_info *input_prims;
const struct draw_vertex_info *input_verts;
bool needs_primid;
int primid_slot;
unsigned primid;
unsigned num_prims;
};
static bool
needs_primid(const struct draw_context *draw)
{
const struct draw_fragment_shader *fs = draw->fs.fragment_shader;
const struct draw_geometry_shader *gs = draw->gs.geometry_shader;
const struct draw_tess_eval_shader *tes = draw->tes.tess_eval_shader;
if (fs && fs->info.uses_primid) {
if (gs)
return !gs->info.uses_primid;
else if (tes)
return !tes->info.uses_primid;
else
return true;
}
return false;
}
bool
draw_prim_assembler_is_required(const struct draw_context *draw,
const struct draw_prim_info *prim_info,
const struct draw_vertex_info *vert_info)
{
/* viewport index requires primitive boundaries to get correct vertex */
if (draw_current_shader_uses_viewport_index(draw))
return true;
switch (prim_info->prim) {
case MESA_PRIM_LINES_ADJACENCY:
case MESA_PRIM_LINE_STRIP_ADJACENCY:
case MESA_PRIM_TRIANGLES_ADJACENCY:
case MESA_PRIM_TRIANGLE_STRIP_ADJACENCY:
return true;
default:
return needs_primid(draw);
}
}
static void
add_prim(struct draw_assembler *asmblr, unsigned length)
{
struct draw_prim_info *output_prims = asmblr->output_prims;
output_prims->primitive_lengths = realloc(output_prims->primitive_lengths, sizeof(unsigned) * (output_prims->primitive_count + 1));
output_prims->primitive_lengths[output_prims->primitive_count] = length;
output_prims->primitive_count++;
}
/*
* Copy the vertex header along with its data from the current
* vertex buffer into a buffer holding vertices arranged
* into decomposed primitives (i.e. buffer without the
* adjacency vertices)
*/
static void
copy_verts(struct draw_assembler *asmblr,
unsigned *indices, unsigned num_indices)
{
char *output = (char*)asmblr->output_verts->verts;
const char *input = (const char*)asmblr->input_verts->verts;
for (unsigned i = 0; i < num_indices; ++i) {
unsigned idx = indices[i];
unsigned output_offset =
asmblr->output_verts->count * asmblr->output_verts->stride;
unsigned input_offset = asmblr->input_verts->stride * idx;
memcpy(output + output_offset, input + input_offset,
asmblr->input_verts->vertex_size);
asmblr->output_verts->count += 1;
}
++asmblr->num_prims;
}
static void
inject_primid(struct draw_assembler *asmblr,
unsigned idx,
unsigned primid)
{
int slot = asmblr->primid_slot;
char *input = (char*)asmblr->input_verts->verts;
unsigned input_offset = asmblr->input_verts->stride * idx;
struct vertex_header *v = (struct vertex_header*)(input + input_offset);
/* In case the backend doesn't care about it */
if (slot < 0) {
return;
}
memcpy(&v->data[slot][0], &primid, sizeof(primid));
memcpy(&v->data[slot][1], &primid, sizeof(primid));
memcpy(&v->data[slot][2], &primid, sizeof(primid));
memcpy(&v->data[slot][3], &primid, sizeof(primid));
}
static void
prim_point(struct draw_assembler *asmblr,
unsigned idx)
{
unsigned indices[1];
if (asmblr->needs_primid) {
inject_primid(asmblr, idx, asmblr->primid++);
}
indices[0] = idx;
add_prim(asmblr, 1);
copy_verts(asmblr, indices, 1);
}
static void
prim_line(struct draw_assembler *asmblr,
unsigned i0, unsigned i1)
{
unsigned indices[2];
if (asmblr->needs_primid) {
inject_primid(asmblr, i0, asmblr->primid);
inject_primid(asmblr, i1, asmblr->primid++);
}
indices[0] = i0;
indices[1] = i1;
add_prim(asmblr, 2);
copy_verts(asmblr, indices, 2);
}
static void
prim_tri(struct draw_assembler *asmblr,
unsigned i0, unsigned i1, unsigned i2)
{
unsigned indices[3];
if (asmblr->needs_primid) {
inject_primid(asmblr, i0, asmblr->primid);
inject_primid(asmblr, i1, asmblr->primid);
inject_primid(asmblr, i2, asmblr->primid++);
}
indices[0] = i0;
indices[1] = i1;
indices[2] = i2;
add_prim(asmblr, 3);
copy_verts(asmblr, indices, 3);
}
static void
prim_quad(struct draw_assembler *asmblr,
unsigned i0, unsigned i1,
unsigned i2, unsigned i3)
{
unsigned indices[4];
if (asmblr->needs_primid) {
inject_primid(asmblr, i0, asmblr->primid);
inject_primid(asmblr, i1, asmblr->primid);
inject_primid(asmblr, i2, asmblr->primid);
inject_primid(asmblr, i3, asmblr->primid++);
}
indices[0] = i0;
indices[1] = i1;
indices[2] = i2;
indices[3] = i3;
add_prim(asmblr, 4);
copy_verts(asmblr, indices, 4);
}
void
draw_prim_assembler_prepare_outputs(struct draw_assembler *ia)
{
struct draw_context *draw = ia->draw;
if (needs_primid(draw)) {
ia->primid_slot = draw_alloc_extra_vertex_attrib(
ia->draw, TGSI_SEMANTIC_PRIMID, 0);
} else {
ia->primid_slot = -1;
}
}
#define FUNC assembler_run_linear
#define GET_ELT(idx) (start + (idx))
#include "draw_prim_assembler_tmp.h"
#define FUNC assembler_run_elts
#define LOCAL_VARS const uint16_t *elts = input_prims->elts;
#define GET_ELT(idx) (elts[start + (idx)])
#include "draw_prim_assembler_tmp.h"
/*
* Primitive assembler breaks up adjacency primitives and assembles
* the base primitives they represent, e.g. vertices forming
* MESA_PRIM_TRIANGLE_STRIP_ADJACENCY
* become vertices forming MESA_PRIM_TRIANGLES
* This is needed because specification says that the adjacency
* primitives are only visible in the geometry shader so we need
* to get rid of them so that the rest of the pipeline can
* process the inputs.
*/
void
draw_prim_assembler_run(struct draw_context *draw,
const struct draw_prim_info *input_prims,
const struct draw_vertex_info *input_verts,
struct draw_prim_info *output_prims,
struct draw_vertex_info *output_verts)
{
struct draw_assembler *asmblr = draw->ia;
unsigned start, i;
unsigned assembled_prim = (input_prims->prim == MESA_PRIM_QUADS ||
input_prims->prim == MESA_PRIM_QUAD_STRIP) ?
MESA_PRIM_QUADS : u_reduced_prim(input_prims->prim);
unsigned max_primitives = u_decomposed_prims_for_vertices(
input_prims->prim, input_prims->count);
unsigned max_verts = mesa_vertices_per_prim(assembled_prim) * max_primitives;
asmblr->output_prims = output_prims;
asmblr->output_verts = output_verts;
asmblr->input_prims = input_prims;
asmblr->input_verts = input_verts;
asmblr->needs_primid = needs_primid(asmblr->draw);
asmblr->num_prims = 0;
output_prims->linear = true;
output_prims->elts = NULL;
output_prims->start = 0;
output_prims->prim = assembled_prim;
output_prims->flags = 0x0;
output_prims->primitive_lengths = MALLOC(sizeof(unsigned));
output_prims->primitive_lengths[0] = 0;
output_prims->primitive_count = 1;
output_verts->vertex_size = input_verts->vertex_size;
output_verts->stride = input_verts->stride;
output_verts->verts = (struct vertex_header*)MALLOC(
input_verts->vertex_size * max_verts + DRAW_EXTRA_VERTICES_PADDING);
output_verts->count = 0;
for (start = i = 0; i < input_prims->primitive_count;
start += input_prims->primitive_lengths[i], i++) {
unsigned count = input_prims->primitive_lengths[i];
if (input_prims->linear) {
assembler_run_linear(asmblr, input_prims, input_verts,
start, count);
} else {
assembler_run_elts(asmblr, input_prims, input_verts,
start, count);
}
}
output_prims->count = output_verts->count;
}
struct draw_assembler *
draw_prim_assembler_create(struct draw_context *draw)
{
struct draw_assembler *ia = CALLOC_STRUCT(draw_assembler);
ia->draw = draw;
return ia;
}
void
draw_prim_assembler_destroy(struct draw_assembler *ia)
{
FREE(ia);
}
/*
* Called at the very begin of the draw call with a new instance
* Used to reset state that should persist between primitive restart.
*/
void
draw_prim_assembler_new_instance(struct draw_assembler *asmblr)
{
asmblr->primid = 0;
}
@@ -0,0 +1,77 @@
/**************************************************************************
*
* Copyright 2013 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 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 ITS 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.
*
**************************************************************************/
/*
* Input assembler needs to be able to decompose adjacency primitives
* into something that can be understood by the rest of the pipeline.
* The specs say that the adjacency primitives are *only* visible
* in the geometry shader, for everything else they need to be
* decomposed. Which in most of the cases is not an issue, because the
* geometry shader always decomposes them for us, but without geometry
* shader we were passing unchanged adjacency primitives to the
* rest of the pipeline and causing crashes everywhere.
* If geometry shader is missing and the input primitive is one of
* the adjacency primitives we use the code from this file to
* decompose them into something that the rest of the pipeline can
* understand.
*
*/
#ifndef DRAW_PRIM_ASSEMBLER_H
#define DRAW_PRIM_ASSEMBLER_H
#include "draw/draw_private.h"
struct draw_assembler;
struct draw_assembler *
draw_prim_assembler_create(struct draw_context *draw);
void
draw_prim_assembler_destroy(struct draw_assembler *ia);
bool
draw_prim_assembler_is_required(const struct draw_context *draw,
const struct draw_prim_info *prim_info,
const struct draw_vertex_info *vert_info);
void
draw_prim_assembler_run(struct draw_context *draw,
const struct draw_prim_info *in_prim_info,
const struct draw_vertex_info *in_vert_info,
struct draw_prim_info *out_prim_info,
struct draw_vertex_info *out_vert_info);
void
draw_prim_assembler_prepare_outputs(struct draw_assembler *ia);
void
draw_prim_assembler_new_instance(struct draw_assembler *ia);
#endif
@@ -0,0 +1,28 @@
#define FUNC_VARS \
struct draw_assembler *asmblr, \
const struct draw_prim_info *input_prims, \
const struct draw_vertex_info *input_verts, \
unsigned start, \
unsigned count
#define FUNC_ENTER \
/* declare more local vars */ \
const enum mesa_prim prim = input_prims->prim; \
const unsigned prim_flags = input_prims->flags; \
const bool last_vertex_last = !asmblr->draw->rasterizer->flatshade_first; \
switch (prim) { \
case MESA_PRIM_POLYGON: \
assert(!"unexpected primitive type in prim assembler"); \
return; \
default: \
break; \
}
#define PASS_QUADS
#define POINT(i0) prim_point(asmblr, i0)
#define LINE(flags, i0, i1) prim_line(asmblr, i0, i1)
#define TRIANGLE(flags, i0, i1, i2) prim_tri(asmblr, i0, i1, i2)
#define QUAD(flags, i0, i1, i2, i3) prim_quad(asmblr, i0, i1, i2, i3)
#include "draw_decompose_tmp.h"
+549
View File
@@ -0,0 +1,549 @@
/**************************************************************************
*
* Copyright 2007 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 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 ITS 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.
*
**************************************************************************/
/**
* Private data structures, etc for the draw module.
*/
/**
* Authors:
* Keith Whitwell <[email protected]>
* Brian Paul
*/
#ifndef DRAW_PRIVATE_H
#define DRAW_PRIVATE_H
#include "pipe/p_state.h"
#include "pipe/p_defines.h"
#include "pipe/p_shader_tokens.h"
#include "util/mesa-blake3.h"
#include "draw_vertex_header.h"
#if DRAW_LLVM_AVAILABLE
struct gallivm_state;
#endif
/**
* The max stage the draw stores resources for.
* i.e. vs, tcs, tes, gs. no fs/cs/ms/ts.
*/
#define DRAW_MAX_SHADER_STAGE (MESA_SHADER_GEOMETRY + 1)
/**
* The largest possible index of a vertex that can be fetched.
*/
#define DRAW_MAX_FETCH_IDX 0xffffffff
/**
* Maximum number of extra shader outputs. These are allocated by:
* - draw_pipe_aaline.c (1)
* - draw_pipe_aapoint.c (1)
* - draw_pipe_unfilled.c (1)
* - draw_pipe_wide_point.c (up to 32)
* - draw_prim_assembler.c (1)
*/
#define DRAW_MAX_EXTRA_SHADER_OUTPUTS 32
/**
* Despite some efforts to determine the number of extra shader outputs ahead
* of time, the matter of fact is that this number will vary as primitives
* flow through the draw pipeline. In particular, aaline/aapoint stages
* only allocate their extra shader outputs on the first line/point.
*
* Consequently dup_vert() ends up copying vertices larger than those
* allocated.
*
* Ideally we'd keep track of incoming/outgoing vertex sizes (and strides)
* throughout the draw pipeline, but unfortunately we recompute these all over
* the place, so preemptively expanding the vertex stride/size does not work
* as mismatches ensue.
*
* As stopgap to prevent buffer read overflows, we allocate an extra bit of
* padding at the end of temporary vertex buffers, allowing dup_vert() to copy
* more vertex attributes than allocated.
*/
#define DRAW_EXTRA_VERTICES_PADDING \
(DRAW_MAX_EXTRA_SHADER_OUTPUTS * sizeof(float[4]))
struct pipe_context;
struct draw_vertex_shader;
struct draw_stage;
struct draw_pt_front_end;
struct draw_assembler;
struct draw_llvm;
struct vbuf_render;
struct tgsi_exec_machine;
struct tgsi_sampler;
struct tgsi_image;
struct tgsi_buffer;
struct lp_cached_code;
struct draw_vertex_info;
struct draw_prim_info;
/**
* Represents the mapped vertex buffer.
*/
struct draw_vertex_buffer {
const void *map;
uint32_t size;
};
/* NOTE: It should match vertex_id size above */
#define UNDEFINED_VERTEX_ID 0xffff
/* maximum number of shader variants we can cache */
#define DRAW_MAX_SHADER_VARIANTS 512
struct draw_buffer_info {
const void *ptr;
unsigned size;
};
/**
* Private context for the drawing module.
*/
struct draw_context
{
struct pipe_context *pipe;
/** Drawing/primitive pipeline stages */
struct {
struct draw_stage *first; /**< one of the following */
struct draw_stage *validate;
/* stages (in logical order) */
struct draw_stage *flatshade;
struct draw_stage *clip;
struct draw_stage *cull;
struct draw_stage *user_cull;
struct draw_stage *twoside;
struct draw_stage *offset;
struct draw_stage *unfilled;
struct draw_stage *stipple;
struct draw_stage *aapoint;
struct draw_stage *aaline;
struct draw_stage *pstipple;
struct draw_stage *wide_line;
struct draw_stage *wide_point;
struct draw_stage *rasterize;
float wide_point_threshold; /**< convert pnts to tris if larger than this */
float wide_line_threshold; /**< convert lines to tris if wider than this */
bool wide_point_sprites; /**< convert points to tris for sprite mode */
bool line_stipple; /**< do line stipple? */
bool point_sprite; /**< convert points to quads for sprites? */
/* Temporary storage while the pipeline is being run:
*/
char *verts;
unsigned vertex_stride;
unsigned vertex_count;
} pipeline;
struct vbuf_render *render;
/* Support prototype passthrough path:
*/
struct {
/* Current active frontend */
struct draw_pt_front_end *frontend;
enum mesa_prim prim;
uint8_t vertices_per_patch;
bool rebind_parameters;
unsigned opt; /**< bitmask of PT_x flags */
unsigned eltSize; /* saved eltSize for flushing */
unsigned viewid; /* saved viewid for flushing */
struct {
struct draw_pt_middle_end *fetch_shade_emit;
struct draw_pt_middle_end *general;
struct draw_pt_middle_end *llvm;
struct draw_pt_middle_end *mesh;
} middle;
struct {
struct draw_pt_front_end *vsplit;
} front;
struct pipe_vertex_buffer vertex_buffer[PIPE_MAX_ATTRIBS];
unsigned nr_vertex_buffers;
/*
* This is the largest legal index value for the current set of
* bound vertex buffers. Regardless of any other consideration,
* all vertex lookups need to be clamped to 0..max_index to
* prevent out-of-bound access.
*/
unsigned max_index;
unsigned vertex_strides[PIPE_MAX_ATTRIBS];
struct pipe_vertex_element vertex_element[PIPE_MAX_ATTRIBS];
unsigned nr_vertex_elements;
bool test_fse; /* enable FSE even though its not correct (eg for softpipe) */
bool no_fse; /* disable FSE even when it is correct */
/* user-space vertex data, buffers */
struct {
/** vertex element/index buffer (ex: glDrawElements) */
const void *elts;
/** bytes per index (0, 1, 2 or 4) */
unsigned eltSizeIB;
unsigned eltSize;
unsigned eltMax;
int eltBias;
unsigned min_index;
unsigned max_index;
unsigned drawid;
bool increment_draw_id;
unsigned viewid;
/** vertex arrays */
struct draw_vertex_buffer vbuffer[PIPE_MAX_ATTRIBS];
/** constant buffers for each shader stage */
struct draw_buffer_info constants[DRAW_MAX_SHADER_STAGE][PIPE_MAX_CONSTANT_BUFFERS];
struct draw_buffer_info ssbos[DRAW_MAX_SHADER_STAGE][PIPE_MAX_SHADER_BUFFERS];
/* pointer to planes */
float (*planes)[DRAW_TOTAL_CLIP_PLANES][4];
} user;
} pt;
struct {
bool bypass_clip_xy;
bool bypass_clip_z;
bool guard_band_xy;
bool bypass_clip_points_lines;
} driver;
unsigned fpstate; /**< saved FP state */
bool quads_always_flatshade_last;
bool flushing; /**< debugging/sanity */
bool suspend_flushing; /**< internally set */
/* Flags set if API requires clipping in these planes and the
* driver doesn't indicate that it can do it for us.
*/
bool clip_xy;
bool clip_z;
bool clip_user;
bool guard_band_xy;
bool guard_band_points_lines_xy;
bool dump_vs;
bool identity_viewport;
bool bypass_viewport;
/** Depth format and bias related settings. */
bool floating_point_depth;
double mrd; /**< minimum resolvable depth value, for polygon offset */
/** Current rasterizer state given to us by the driver */
const struct pipe_rasterizer_state *rasterizer;
/** Driver CSO handle for the current rasterizer state */
void *rast_handle;
/** Rasterizer CSOs without culling/stipple/etc */
void *rasterizer_no_cull[2][2][2];
struct pipe_viewport_state viewports[PIPE_MAX_VIEWPORTS];
/** Vertex shader state */
struct {
struct draw_vertex_shader *vertex_shader;
unsigned num_vs_outputs; /**< convenience, from vertex_shader */
unsigned position_output;
unsigned edgeflag_output;
unsigned clipvertex_output;
unsigned ccdistance_output[2];
/** Fields for TGSI interpreter / execution */
struct {
struct tgsi_exec_machine *machine;
struct tgsi_sampler *sampler;
struct tgsi_image *image;
struct tgsi_buffer *buffer;
} tgsi;
struct translate *fetch;
struct translate_cache *fetch_cache;
struct translate *emit;
struct translate_cache *emit_cache;
} vs;
/** Geometry shader state */
struct {
struct draw_geometry_shader *geometry_shader;
unsigned num_gs_outputs; /**< convenience, from geometry_shader */
unsigned position_output;
unsigned clipvertex_output;
/** Fields for TGSI interpreter / execution */
struct {
struct tgsi_exec_machine *machine;
struct tgsi_sampler *sampler;
struct tgsi_image *image;
struct tgsi_buffer *buffer;
} tgsi;
} gs;
/* Tessellation state */
struct {
struct draw_tess_ctrl_shader *tess_ctrl_shader;
} tcs;
struct {
struct draw_tess_eval_shader *tess_eval_shader;
unsigned num_tes_outputs; /**< convenience, from tess_eval_shader */
unsigned position_output;
unsigned clipvertex_output;
} tes;
/** Fragment shader state */
struct {
struct draw_fragment_shader *fragment_shader;
} fs;
struct {
struct draw_mesh_shader *mesh_shader;
unsigned num_ms_outputs; /**< convenience, from geometry_shader */
unsigned position_output;
unsigned clipvertex_output;
} ms;
/** Stream output (vertex feedback) state */
struct {
struct draw_so_target *targets[PIPE_MAX_SO_BUFFERS];
unsigned num_targets;
} so;
/* Clip derived state:
*/
float plane[DRAW_TOTAL_CLIP_PLANES][4];
uint32_t viewmask;
/* If a prim stage introduces new vertex attributes, they'll be stored here
*/
struct {
unsigned num;
enum tgsi_semantic semantic_name[DRAW_MAX_EXTRA_SHADER_OUTPUTS];
unsigned semantic_index[DRAW_MAX_EXTRA_SHADER_OUTPUTS];
unsigned slot[DRAW_MAX_EXTRA_SHADER_OUTPUTS];
} extra_shader_outputs;
unsigned instance_id;
unsigned start_instance;
unsigned start_index;
unsigned constant_buffer_stride;
struct draw_llvm *llvm;
/** Texture sampler and sampler view state.
* Note that we have arrays indexed by shader type. At this time
* we only handle vertex and geometry shaders in the draw module, but
* there may be more in the future (ex: hull and tessellation).
*/
struct pipe_sampler_view *sampler_views[DRAW_MAX_SHADER_STAGE][PIPE_MAX_SHADER_SAMPLER_VIEWS];
unsigned num_sampler_views[DRAW_MAX_SHADER_STAGE];
const struct pipe_sampler_state *samplers[DRAW_MAX_SHADER_STAGE][PIPE_MAX_SAMPLERS];
unsigned num_samplers[DRAW_MAX_SHADER_STAGE];
struct pipe_image_view *images[DRAW_MAX_SHADER_STAGE][PIPE_MAX_SHADER_IMAGES];
unsigned num_images[DRAW_MAX_SHADER_STAGE];
struct pipe_query_data_pipeline_statistics statistics;
bool collect_statistics;
bool collect_primgen;
float default_outer_tess_level[4];
float default_inner_tess_level[2];
struct draw_assembler *ia;
void *disk_cache_cookie;
void (*disk_cache_find_shader)(void *cookie,
struct lp_cached_code *cache,
unsigned char ir_blake3_cache_key[BLAKE3_KEY_LEN]);
void (*disk_cache_insert_shader)(void *cookie,
struct lp_cached_code *cache,
unsigned char ir_blake3_cache_key[BLAKE3_KEY_LEN]);
void *driver_private;
};
struct draw_fetch_info {
bool linear;
unsigned start;
const unsigned *elts;
unsigned count;
};
/* these flags are set if the primitive is a segment of a larger one */
#define DRAW_SPLIT_BEFORE 0x1
#define DRAW_SPLIT_AFTER 0x2
#define DRAW_LINE_LOOP_AS_STRIP 0x4
/*******************************************************************************
* Draw common initialization code
*/
bool draw_init(struct draw_context *draw);
void draw_new_instance(struct draw_context *draw);
/*******************************************************************************
* Vertex shader code:
*/
bool draw_vs_init(struct draw_context *draw);
void draw_vs_destroy(struct draw_context *draw);
/*******************************************************************************
* Geometry shading code:
*/
bool draw_gs_init(struct draw_context *draw);
void draw_gs_destroy(struct draw_context *draw);
/*******************************************************************************
* Common shading code:
*/
unsigned draw_current_shader_outputs(const struct draw_context *draw);
unsigned draw_current_shader_position_output(const struct draw_context *draw);
unsigned draw_current_shader_viewport_index_output(const struct draw_context *draw);
unsigned draw_current_shader_clipvertex_output(const struct draw_context *draw);
unsigned draw_current_shader_ccdistance_output(const struct draw_context *draw, int index);
unsigned draw_current_shader_num_written_clipdistances(const struct draw_context *draw);
unsigned draw_current_shader_num_written_culldistances(const struct draw_context *draw);
int draw_alloc_extra_vertex_attrib(struct draw_context *draw,
enum tgsi_semantic semantic_name,
unsigned semantic_index);
void draw_remove_extra_vertex_attribs(struct draw_context *draw);
bool draw_current_shader_uses_viewport_index(
const struct draw_context *draw);
/*******************************************************************************
* Vertex processing (was passthrough) code:
*/
bool draw_pt_init(struct draw_context *draw);
void draw_pt_destroy(struct draw_context *draw);
void draw_pt_reset_vertex_ids(struct draw_context *draw);
void draw_pt_flush(struct draw_context *draw, unsigned flags);
/*******************************************************************************
* Primitive processing (pipeline) code:
*/
bool draw_pipeline_init(struct draw_context *draw);
void draw_pipeline_destroy(struct draw_context *draw);
/*
* These flags are used by the pipeline when unfilled and/or line stipple modes
* are operational.
*/
#define DRAW_PIPE_EDGE_FLAG_0 0x1
#define DRAW_PIPE_EDGE_FLAG_1 0x2
#define DRAW_PIPE_EDGE_FLAG_2 0x4
#define DRAW_PIPE_EDGE_FLAG_ALL 0x7
#define DRAW_PIPE_RESET_STIPPLE 0x8
void
draw_pipeline_run(struct draw_context *draw,
const struct draw_vertex_info *vert,
const struct draw_prim_info *prim);
void
draw_pipeline_run_linear(struct draw_context *draw,
const struct draw_vertex_info *vert,
const struct draw_prim_info *prim);
void
draw_pipeline_flush(struct draw_context *draw,
unsigned flags);
/*
* Flushing
*/
#define DRAW_FLUSH_PARAMETER_CHANGE 0x1 /**< Constants, viewport, etc */
#define DRAW_FLUSH_STATE_CHANGE 0x2 /**< Other/heavy state changes */
#define DRAW_FLUSH_BACKEND 0x4 /**< Flush the output buffer */
void
draw_do_flush(struct draw_context *draw, unsigned flags);
void *
draw_get_rasterizer_no_cull(struct draw_context *draw,
const struct pipe_rasterizer_state *rast);
void
draw_stats_clipper_primitives(struct draw_context *draw,
const struct draw_prim_info *prim_info);
void
draw_update_clip_flags(struct draw_context *draw);
void
draw_update_viewport_flags(struct draw_context *draw);
/**
* Return index i from the index buffer.
* If the index buffer would overflow we return index 0.
*/
#define DRAW_GET_IDX(_elts, _i) \
(((_i) >= draw->pt.user.eltMax) ? 0 : (_elts)[_i])
/**
* Return index of the given viewport clamping it
* to be between 0 <= and < PIPE_MAX_VIEWPORTS
*/
static inline unsigned
draw_clamp_viewport_idx(int idx)
{
return ((PIPE_MAX_VIEWPORTS > idx && idx >= 0) ? idx : 0);
}
#endif /* DRAW_PRIVATE_H */
+655
View File
@@ -0,0 +1,655 @@
/**************************************************************************
*
* Copyright 2007 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 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 ITS 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.
*
**************************************************************************/
/*
* Authors:
* Keith Whitwell <[email protected]>
*/
#include "draw/draw_context.h"
#include "draw/draw_gs.h"
#include "draw/draw_tess.h"
#include "draw/draw_private.h"
#include "draw/draw_pt.h"
#include "draw/draw_vbuf.h"
#include "draw/draw_vs.h"
#include "tgsi/tgsi_dump.h"
#include "util/u_math.h"
#include "util/u_prim.h"
#include "util/format/u_format.h"
#include "util/u_draw.h"
DEBUG_GET_ONCE_BOOL_OPTION(draw_fse, "DRAW_FSE", false)
DEBUG_GET_ONCE_BOOL_OPTION(draw_no_fse, "DRAW_NO_FSE", false)
/* Overall we split things into:
* - frontend -- prepare fetch_elts, draw_elts - eg vsplit
* - middle -- fetch, shade, cliptest, viewport
* - pipeline -- the prim pipeline: clipping, wide lines, etc
* - backend -- the vbuf_render provided by the driver.
*/
static bool
draw_pt_arrays(struct draw_context *draw,
enum mesa_prim prim,
bool index_bias_varies,
const struct pipe_draw_start_count_bias *draw_info,
unsigned num_draws)
{
enum mesa_prim out_prim = prim;
if (draw->gs.geometry_shader)
out_prim = draw->gs.geometry_shader->output_primitive;
else if (draw->tes.tess_eval_shader)
out_prim = get_tes_output_prim(draw->tes.tess_eval_shader);
unsigned opt = PT_SHADE;
if (!draw->render) {
opt |= PT_PIPELINE;
}
if (draw_need_pipeline(draw, draw->rasterizer, out_prim)) {
opt |= PT_PIPELINE;
}
if ((draw->clip_xy ||
draw->clip_z ||
draw->clip_user) && !draw->pt.test_fse) {
opt |= PT_CLIPTEST;
}
struct draw_pt_middle_end *middle;
if (draw->pt.middle.llvm) {
middle = draw->pt.middle.llvm;
} else {
if (opt == PT_SHADE && !draw->pt.no_fse)
middle = draw->pt.middle.fetch_shade_emit;
else
middle = draw->pt.middle.general;
}
struct draw_pt_front_end *frontend = draw->pt.frontend;
if (frontend) {
if (draw->pt.prim != prim || draw->pt.opt != opt) {
/* In certain conditions switching primitives requires us to flush
* and validate the different stages. One example is when smooth
* lines are active but first drawn with triangles and then with
* lines.
*/
draw_do_flush(draw, DRAW_FLUSH_STATE_CHANGE);
frontend = NULL;
} else if (draw->pt.eltSize != draw->pt.user.eltSize || draw->pt.viewid != draw->pt.user.viewid) {
/* Flush draw state if eltSize or viewid changed.
* eltSize changes could be improved so only the frontend is flushed since it
* converts all indices to ushorts and the fetch part of the middle
* always prepares both linear and indexed.
*/
frontend->flush(frontend, DRAW_FLUSH_STATE_CHANGE);
frontend = NULL;
}
}
if (!frontend) {
frontend = draw->pt.front.vsplit;
frontend->prepare(frontend, prim, middle, opt);
draw->pt.frontend = frontend;
draw->pt.eltSize = draw->pt.user.eltSize;
draw->pt.viewid = draw->pt.user.viewid;
draw->pt.prim = prim;
draw->pt.opt = opt;
}
if (draw->pt.rebind_parameters) {
/* update constants, viewport dims, clip planes, etc */
middle->bind_parameters(middle);
draw->pt.rebind_parameters = false;
}
for (unsigned i = 0; i < num_draws; i++) {
/* Sanitize primitive length:
*/
unsigned first, incr;
if (prim == MESA_PRIM_PATCHES) {
first = draw->pt.vertices_per_patch;
incr = draw->pt.vertices_per_patch;
} else {
draw_pt_split_prim(prim, &first, &incr);
}
unsigned count = draw_pt_trim_count(draw_info[i].count, first, incr);
if (draw->pt.user.eltSize) {
if (index_bias_varies) {
draw->pt.user.eltBias = draw_info[i].index_bias;
} else {
draw->pt.user.eltBias = draw_info[0].index_bias;
}
} else {
draw->pt.user.eltBias = 0;
}
draw->start_index = draw_info[i].start;
if (count >= first)
frontend->run(frontend, draw_info[i].start, count);
if (num_draws > 1 && draw->pt.user.increment_draw_id)
draw->pt.user.drawid++;
}
return true;
}
void
draw_pt_flush(struct draw_context *draw, unsigned flags)
{
assert(flags);
if (draw->pt.frontend) {
draw->pt.frontend->flush(draw->pt.frontend, flags);
/* don't prepare if we only are flushing the backend */
if (flags & DRAW_FLUSH_STATE_CHANGE)
draw->pt.frontend = NULL;
}
if (flags & DRAW_FLUSH_PARAMETER_CHANGE) {
draw->pt.rebind_parameters = true;
}
}
bool
draw_pt_init(struct draw_context *draw)
{
draw->pt.test_fse = debug_get_option_draw_fse();
draw->pt.no_fse = debug_get_option_draw_no_fse();
draw->pt.front.vsplit = draw_pt_vsplit(draw);
if (!draw->pt.front.vsplit)
return false;
draw->pt.middle.fetch_shade_emit = draw_pt_middle_fse(draw);
if (!draw->pt.middle.fetch_shade_emit)
return false;
draw->pt.middle.general = draw_pt_fetch_pipeline_or_emit(draw);
if (!draw->pt.middle.general)
return false;
#if DRAW_LLVM_AVAILABLE
if (draw->llvm) {
draw->pt.middle.llvm = draw_pt_fetch_pipeline_or_emit_llvm(draw);
draw->pt.middle.mesh = draw_pt_mesh_pipeline_or_emit(draw);
}
#endif
return true;
}
void
draw_pt_destroy(struct draw_context *draw)
{
if (draw->pt.middle.mesh) {
draw->pt.middle.mesh->destroy(draw->pt.middle.mesh);
draw->pt.middle.mesh = NULL;
}
if (draw->pt.middle.llvm) {
draw->pt.middle.llvm->destroy(draw->pt.middle.llvm);
draw->pt.middle.llvm = NULL;
}
if (draw->pt.middle.general) {
draw->pt.middle.general->destroy(draw->pt.middle.general);
draw->pt.middle.general = NULL;
}
if (draw->pt.middle.fetch_shade_emit) {
draw->pt.middle.fetch_shade_emit->destroy(draw->pt.middle.fetch_shade_emit);
draw->pt.middle.fetch_shade_emit = NULL;
}
if (draw->pt.front.vsplit) {
draw->pt.front.vsplit->destroy(draw->pt.front.vsplit);
draw->pt.front.vsplit = NULL;
}
}
/**
* Debug- print the first 'count' vertices.
*/
static void
draw_print_arrays(struct draw_context *draw, enum mesa_prim prim,
int start, unsigned count, int index_bias)
{
debug_printf("Draw arrays(prim = %u, start = %u, count = %u)\n",
prim, start, count);
for (unsigned i = 0; i < count; i++) {
unsigned ii = 0;
if (draw->pt.user.eltSize) {
/* indexed arrays */
switch (draw->pt.user.eltSize) {
case 1:
{
const uint8_t *elem = (const uint8_t *) draw->pt.user.elts;
ii = elem[start + i];
}
break;
case 2:
{
const uint16_t *elem = (const uint16_t *) draw->pt.user.elts;
ii = elem[start + i];
}
break;
case 4:
{
const uint32_t *elem = (const uint32_t *) draw->pt.user.elts;
ii = elem[start + i];
}
break;
default:
assert(0);
return;
}
ii += index_bias;
debug_printf("Element[%u + %u] + %i -> Vertex %u:\n", start, i,
index_bias, ii);
}
else {
/* non-indexed arrays */
ii = start + i;
debug_printf("Vertex %u:\n", ii);
}
for (unsigned j = 0; j < draw->pt.nr_vertex_elements; j++) {
unsigned buf = draw->pt.vertex_element[j].vertex_buffer_index;
uint8_t *ptr = (uint8_t *) draw->pt.user.vbuffer[buf].map;
if (draw->pt.vertex_element[j].instance_divisor) {
ii = draw->instance_id / draw->pt.vertex_element[j].instance_divisor;
}
ptr += draw->pt.vertex_buffer[buf].buffer_offset;
ptr += draw->pt.vertex_element[j].src_stride * ii;
ptr += draw->pt.vertex_element[j].src_offset;
debug_printf(" Attr %u: ", j);
switch (draw->pt.vertex_element[j].src_format) {
case PIPE_FORMAT_R32_FLOAT:
{
float *v = (float *) ptr;
debug_printf("R %f @ %p\n", v[0], (void *) v);
}
break;
case PIPE_FORMAT_R32G32_FLOAT:
{
float *v = (float *) ptr;
debug_printf("RG %f %f @ %p\n", v[0], v[1], (void *) v);
}
break;
case PIPE_FORMAT_R32G32B32_FLOAT:
{
float *v = (float *) ptr;
debug_printf("RGB %f %f %f @ %p\n", v[0], v[1], v[2], (void *) v);
}
break;
case PIPE_FORMAT_R32G32B32A32_FLOAT:
{
float *v = (float *) ptr;
debug_printf("RGBA %f %f %f %f @ %p\n", v[0], v[1], v[2], v[3],
(void *) v);
}
break;
case PIPE_FORMAT_B8G8R8A8_UNORM:
{
uint8_t *u = (uint8_t *) ptr;
debug_printf("BGRA %d %d %d %d @ %p\n", u[0], u[1], u[2], u[3],
(void *) u);
}
break;
case PIPE_FORMAT_A8R8G8B8_UNORM:
{
uint8_t *u = (uint8_t *) ptr;
debug_printf("ARGB %d %d %d %d @ %p\n", u[0], u[1], u[2], u[3],
(void *) u);
}
break;
default:
debug_printf("other format %s (fix me)\n",
util_format_name(draw->pt.vertex_element[j].src_format));
}
}
}
}
/** Helper code for below */
static inline void
prim_restart_loop(struct draw_context *draw,
const struct pipe_draw_info *info,
const struct pipe_draw_start_count_bias *draw_info,
const void *elements)
{
const unsigned elt_max = draw->pt.user.eltMax;
struct pipe_draw_start_count_bias cur = *draw_info;
cur.count = 0;
for (unsigned j = 0; j < draw_info->count; j++) {
unsigned index = 0;
unsigned i = util_clamped_uadd(draw_info->start, j);
if (i < elt_max) {
switch (draw->pt.user.eltSize) {
case 1:
index = ((const uint8_t*)elements)[i];
break;
case 2:
index = ((const uint16_t*)elements)[i];
break;
case 4:
index = ((const uint32_t*)elements)[i];
break;
default:
assert(0 && "bad eltSize in draw_arrays()");
}
}
if (index == info->restart_index) {
if (cur.count > 0) {
/* draw elts up to prev pos */
draw_pt_arrays(draw, info->mode, info->index_bias_varies, &cur, 1);
}
/* begin new prim at next elt */
cur.start = i + 1;
cur.count = 0;
}
else {
cur.count++;
}
}
if (cur.count > 0) {
draw_pt_arrays(draw, info->mode, info->index_bias_varies, &cur, 1);
}
}
/**
* For drawing prims with primitive restart enabled.
* Scan for restart indexes and draw the runs of elements/vertices between
* the restarts.
*/
static void
draw_pt_arrays_restart(struct draw_context *draw,
const struct pipe_draw_info *info,
const struct pipe_draw_start_count_bias *draw_info,
unsigned num_draws)
{
assert(info->primitive_restart);
if (draw->pt.user.eltSize) {
/* indexed prims (draw_elements) */
for (unsigned i = 0; i < num_draws; i++)
prim_restart_loop(draw, info, &draw_info[i], draw->pt.user.elts);
} else {
/* Non-indexed prims (draw_arrays).
* Primitive restart should have been handled in gallium frontends.
*/
draw_pt_arrays(draw, info->mode, info->index_bias_varies, draw_info, num_draws);
}
}
/**
* Resolve true values within pipe_draw_info.
* If we're rendering from transform feedback/stream output
* buffers both the count and max_index need to be computed
* from the attached stream output target.
*/
static void
resolve_draw_info(const struct pipe_draw_info *raw_info,
const struct pipe_draw_indirect_info *indirect,
const struct pipe_draw_start_count_bias *raw_draw,
struct pipe_draw_info *info,
struct pipe_draw_start_count_bias *draw,
struct pipe_vertex_buffer *vertex_buffer,
struct pipe_vertex_element *vertex_element)
{
*info = *raw_info;
*draw = *raw_draw;
struct draw_so_target *target =
(struct draw_so_target *)indirect->count_from_stream_output;
assert(vertex_buffer != NULL);
draw->count = vertex_element->src_stride == 0 ? 0 :
target->internal_offset / vertex_element->src_stride;
/* Stream output draw can not be indexed */
assert(!info->index_size);
info->max_index = draw->count - 1;
}
/*
* Loop over all instances and execute draws for them.
*/
static void
draw_instances(struct draw_context *draw,
unsigned drawid_offset,
const struct pipe_draw_info *info,
const struct pipe_draw_start_count_bias *draws,
unsigned num_draws)
{
draw->start_instance = info->start_instance;
for (unsigned instance = 0; instance < info->instance_count; instance++) {
unsigned instance_idx = instance + info->start_instance;
draw->instance_id = instance;
/* check for overflow */
if (instance_idx < instance ||
instance_idx < draw->start_instance) {
/* if we overflown just set the instance id to the max */
draw->instance_id = 0xffffffff;
}
draw->pt.user.drawid = drawid_offset;
draw_new_instance(draw);
if (info->primitive_restart) {
draw_pt_arrays_restart(draw, info, draws, num_draws);
} else {
draw_pt_arrays(draw, info->mode, info->index_bias_varies,
draws, num_draws);
}
}
}
/**
* Draw vertex arrays.
* This is the main entrypoint into the drawing module. If drawing an indexed
* primitive, the draw_set_indexes() function should have already been called
* to specify the element/index buffer information.
*/
void
draw_vbo(struct draw_context *draw,
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,
uint8_t patch_vertices)
{
struct pipe_draw_info resolved_info;
struct pipe_draw_start_count_bias resolved_draw;
const struct pipe_draw_info *use_info;
const struct pipe_draw_start_count_bias *use_draws;
if (info->instance_count == 0)
return;
/* Make sure that denorms are treated like zeros. This is
* the behavior required by D3D10. OpenGL doesn't care.
*/
draw->fpstate = util_fpstate_get();
util_fpstate_set_denorms_to_zero(draw->fpstate);
if (indirect && indirect->count_from_stream_output) {
resolve_draw_info(info, indirect, &draws[0], &resolved_info,
&resolved_draw, &(draw->pt.vertex_buffer[0]),
&(draw->pt.vertex_element[0]));
use_info = &resolved_info;
use_draws = &resolved_draw;
num_draws = 1;
} else {
use_info = info;
use_draws = draws;
}
if (info->index_size) {
assert(draw->pt.user.elts);
draw->pt.user.min_index = use_info->index_bounds_valid ? use_info->min_index : 0;
draw->pt.user.max_index = use_info->index_bounds_valid ? use_info->max_index : ~0;
} else {
draw->pt.user.min_index = 0;
draw->pt.user.max_index = ~0;
}
draw->pt.user.eltSize = use_info->index_size ? draw->pt.user.eltSizeIB : 0;
draw->pt.user.drawid = drawid_offset;
draw->pt.user.increment_draw_id = use_info->increment_draw_id;
draw->pt.user.viewid = 0;
draw->pt.vertices_per_patch = patch_vertices;
if (0) {
for (unsigned i = 0; i < num_draws; i++)
debug_printf("draw_vbo(mode=%u start=%u count=%u):\n",
use_info->mode, use_draws[i].start, use_draws[i].count);
}
if (0)
tgsi_dump(draw->vs.vertex_shader->state.tokens, 0);
if (0) {
debug_printf("Elements:\n");
for (unsigned i = 0; i < draw->pt.nr_vertex_elements; i++) {
debug_printf(" %u: src_offset=%u src_stride=%u inst_div=%u vbuf=%u format=%s\n",
i,
draw->pt.vertex_element[i].src_offset,
draw->pt.vertex_element[i].src_stride,
draw->pt.vertex_element[i].instance_divisor,
draw->pt.vertex_element[i].vertex_buffer_index,
util_format_name(draw->pt.vertex_element[i].src_format));
}
debug_printf("Buffers:\n");
for (unsigned i = 0; i < draw->pt.nr_vertex_buffers; i++) {
debug_printf(" %u: offset=%u size=%d ptr=%p\n",
i,
draw->pt.vertex_buffer[i].buffer_offset,
(int) draw->pt.user.vbuffer[i].size,
draw->pt.user.vbuffer[i].map);
}
}
if (0) {
for (unsigned i = 0; i < num_draws; i++)
draw_print_arrays(draw, use_info->mode, use_draws[i].start,
MIN2(use_draws[i].count, 20),
use_info->index_bias_varies
? use_draws[i].index_bias
: use_draws[0].index_bias);
}
unsigned index_limit = util_draw_max_index(draw->pt.vertex_buffer,
draw->pt.vertex_element,
draw->pt.nr_vertex_elements,
use_info);
#if DRAW_LLVM_AVAILABLE
if (!draw->llvm)
#endif
{
if (index_limit == 0) {
/* one of the buffers is too small to do any valid drawing */
debug_warning("draw: VBO too small to draw anything\n");
util_fpstate_set(draw->fpstate);
return;
}
}
/* If we're collecting stats then make sure we start from scratch */
if (draw->collect_statistics) {
memset(&draw->statistics, 0, sizeof(draw->statistics));
}
draw->pt.max_index = index_limit - 1;
/*
* TODO: We could use draw->pt.max_index to further narrow
* the min_index/max_index hints given by gallium frontends.
*/
if (draw->viewmask) {
u_foreach_bit(i, draw->viewmask) {
draw->pt.user.viewid = i;
draw_instances(draw, drawid_offset, use_info, use_draws, num_draws);
}
} else {
draw_instances(draw, drawid_offset, use_info, use_draws, num_draws);
}
/* If requested emit the pipeline statistics for this run */
if (draw->collect_statistics) {
draw->render->pipeline_statistics(draw->render, &draw->statistics);
}
util_fpstate_set(draw->fpstate);
}
/* to be called after a mesh shader is run */
void
draw_mesh(struct draw_context *draw,
struct draw_vertex_info *vert_info,
struct draw_prim_info *prim_info)
{
struct draw_pt_middle_end *middle = draw->pt.middle.mesh;
draw->pt.user.eltSize = 0;
draw->pt.user.viewid = 0;
draw->pt.user.drawid = 0;
draw->pt.user.increment_draw_id = false;
draw->pt.vertices_per_patch = 0;
middle->prepare(middle, 0, 0, NULL);
draw_mesh_middle_end_run(middle, vert_info, prim_info);
}
+276
View File
@@ -0,0 +1,276 @@
/**************************************************************************
*
* Copyright 2007 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 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 ITS 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.
*
**************************************************************************/
/*
* Authors:
* Keith Whitwell <[email protected]>
*/
#ifndef DRAW_PT_H
#define DRAW_PT_H
#include "util/compiler.h"
struct draw_pt_middle_end;
struct draw_context;
struct draw_prim_info;
struct draw_vertex_info;
#define PT_SHADE 0x1
#define PT_CLIPTEST 0x2
#define PT_PIPELINE 0x4
#define PT_MAX_MIDDLE 0x8
/* The "front end" - prepare sets of fetch, draw elements for the
* middle end.
*
* The fetch elements are indices to the vertices. The draw elements are
* indices to the fetched vertices. When both arrays of elements are both
* linear, middle->run_linear is called; When only the fetch elements are
* linear, middle->run_linear_elts is called; Otherwise, middle->run is
* called.
*
* When the number of the draw elements exceeds max_vertex of the middle end,
* the draw elements (as well as the fetch elements) are splitted and the
* middle end is called multiple times.
*
* Currenly there is:
* - vsplit - catchall implementation, splits big prims
*/
struct draw_pt_front_end {
void (*prepare)(struct draw_pt_front_end *,
enum mesa_prim prim,
struct draw_pt_middle_end *,
unsigned opt);
void (*run)(struct draw_pt_front_end *,
unsigned start,
unsigned count);
void (*flush)(struct draw_pt_front_end *, unsigned flags);
void (*destroy)(struct draw_pt_front_end *);
};
/* The "middle end" - prepares actual hardware vertices for the
* hardware backend.
*
* prim_flags is as defined by pipe_draw_info::flags.
*
* Currently two versions of this:
* - fetch, vertex shade, cliptest, prim-pipeline
* - fetch, emit (ie passthrough)
*/
struct draw_pt_middle_end {
void (*prepare)(struct draw_pt_middle_end *,
enum mesa_prim prim,
unsigned opt,
unsigned *max_vertices);
/**
* Bind/update parameter state such as constants, viewport dims
* and clip planes. Basically, stuff which isn't "baked" into the
* shader or pipeline state.
*/
void (*bind_parameters)(struct draw_pt_middle_end *);
void (*run)(struct draw_pt_middle_end *,
unsigned start,
const unsigned *fetch_elts,
unsigned fetch_count,
const uint16_t *draw_elts,
unsigned draw_count,
unsigned prim_flags);
void (*run_linear)(struct draw_pt_middle_end *,
unsigned start,
unsigned count,
unsigned prim_flags);
/* Transform all vertices in a linear range and then draw them with
* the supplied element list. May fail and return FALSE.
*/
bool (*run_linear_elts)(struct draw_pt_middle_end *,
unsigned fetch_start,
unsigned fetch_count,
const uint16_t *draw_elts,
unsigned draw_start,
unsigned draw_count);
int (*get_max_vertex_count)(struct draw_pt_middle_end *);
void (*finish)(struct draw_pt_middle_end *);
void (*destroy)(struct draw_pt_middle_end *);
};
/* The "back end" - supplied by the driver, defined in draw_vbuf.h.
*/
struct vbuf_render;
struct vertex_header;
/* Frontends:
*
* Currently only the general-purpose vsplit implementation.
*/
struct draw_pt_front_end *draw_pt_vsplit(struct draw_context *draw);
/* Middle-ends:
*
* Currently one general-purpose case which can do all possibilities,
* at the slight expense of creating a vertex_header in some cases
* unecessarily.
*/
struct draw_pt_middle_end *draw_pt_middle_fse(struct draw_context *draw);
struct draw_pt_middle_end *draw_pt_fetch_pipeline_or_emit(struct draw_context *draw);
struct draw_pt_middle_end *draw_pt_fetch_pipeline_or_emit_llvm(struct draw_context *draw);
struct draw_pt_middle_end *draw_pt_mesh_pipeline_or_emit(struct draw_context *draw);
/*******************************************************************************
* HW vertex emit:
*/
struct pt_emit;
void
draw_pt_emit_prepare(struct pt_emit *emit,
enum mesa_prim prim,
unsigned *max_vertices);
void
draw_pt_emit(struct pt_emit *emit,
const struct draw_vertex_info *vert_info,
const struct draw_prim_info *prim_info);
void
draw_pt_emit_linear(struct pt_emit *emit,
const struct draw_vertex_info *vert_info,
const struct draw_prim_info *prim_info);
void
draw_pt_emit_destroy(struct pt_emit *emit);
struct pt_emit *
draw_pt_emit_create(struct draw_context *draw);
/*******************************************************************************
* HW stream output emit:
*/
struct pt_so_emit;
void
draw_pt_so_emit_prepare(struct pt_so_emit *emit, bool use_pre_clip_pos);
void
draw_pt_so_emit(struct pt_so_emit *emit,
int num_vertex_streams,
const struct draw_vertex_info *vert_info,
const struct draw_prim_info *prim_info);
void
draw_pt_so_emit_destroy(struct pt_so_emit *emit);
struct pt_so_emit *
draw_pt_so_emit_create(struct draw_context *draw);
/*******************************************************************************
* API vertex fetch:
*/
struct pt_fetch;
void
draw_pt_fetch_prepare(struct pt_fetch *fetch,
unsigned vertex_input_count,
unsigned vertex_size,
unsigned instance_id_index);
void
draw_pt_fetch_run(struct pt_fetch *fetch,
const unsigned *elts,
unsigned count,
char *verts);
void
draw_pt_fetch_run_linear(struct pt_fetch *fetch,
unsigned start,
unsigned count,
char *verts);
void
draw_pt_fetch_destroy(struct pt_fetch *fetch);
struct pt_fetch *
draw_pt_fetch_create(struct draw_context *draw);
/*******************************************************************************
* Post-VS: cliptest, rhw, viewport
*/
struct pt_post_vs;
bool
draw_pt_post_vs_run(struct pt_post_vs *pvs,
struct draw_vertex_info *info,
const struct draw_prim_info *prim_info);
void
draw_pt_post_vs_prepare(struct pt_post_vs *pvs,
bool clip_xy,
bool clip_z,
bool clip_user,
bool guard_band,
bool bypass_viewport,
bool clip_halfz,
bool need_edgeflags);
struct pt_post_vs *
draw_pt_post_vs_create(struct draw_context *draw);
void
draw_pt_post_vs_destroy(struct pt_post_vs *pvs);
/*******************************************************************************
* Utils:
*/
void
draw_pt_split_prim(enum mesa_prim prim, unsigned *first, unsigned *incr);
unsigned
draw_pt_trim_count(unsigned count, unsigned first, unsigned incr);
void
draw_mesh_middle_end_run(struct draw_pt_middle_end *middle,
struct draw_vertex_info *vert_info,
struct draw_prim_info *prim_info);
#endif
@@ -0,0 +1,8 @@
#define LOCAL_VARS \
char *verts = (char *) vertices; \
const bool quads_flatshade_last = \
draw->quads_always_flatshade_last; \
const bool last_vertex_last = \
!draw->rasterizer->flatshade_first;
#include "draw_decompose_tmp.h"
+323
View File
@@ -0,0 +1,323 @@
/**************************************************************************
*
* Copyright 2008 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 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 ITS 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 "util/u_memory.h"
#include "draw/draw_context.h"
#include "draw/draw_private.h"
#include "draw/draw_vbuf.h"
#include "draw/draw_vertex.h"
#include "draw/draw_pt.h"
#include "translate/translate.h"
#include "translate/translate_cache.h"
#include "util/u_prim.h"
struct pt_emit {
struct draw_context *draw;
struct translate *translate;
struct translate_cache *cache;
unsigned prim;
const struct vertex_info *vinfo;
float zero4[4];
};
void
draw_pt_emit_prepare(struct pt_emit *emit,
enum mesa_prim prim,
unsigned *max_vertices)
{
struct draw_context *draw = emit->draw;
const struct vertex_info *vinfo;
struct translate_key hw_key;
/* XXX: need to flush to get prim_vbuf.c to release its allocation??
*/
draw_do_flush(draw, DRAW_FLUSH_BACKEND);
/* XXX: may need to defensively reset this later on as clipping can
* clobber this state in the render backend.
*/
emit->prim = prim;
draw->render->set_primitive(draw->render, emit->prim);
if (draw->render->set_view_index)
draw->render->set_view_index(draw->render, draw->pt.user.viewid);
/* Must do this after set_primitive() above:
*/
emit->vinfo = vinfo = draw->render->get_vertex_info(draw->render);
/* Translate from pipeline vertices to hw vertices.
*/
unsigned dst_offset = 0;
for (unsigned i = 0; i < vinfo->num_attribs; i++) {
unsigned emit_sz = 0;
unsigned src_buffer = 0;
unsigned output_format;
unsigned src_offset = vinfo->attrib[i].src_index * 4 * sizeof(float);
output_format = draw_translate_vinfo_format(vinfo->attrib[i].emit);
emit_sz = draw_translate_vinfo_size(vinfo->attrib[i].emit);
/* doesn't handle EMIT_OMIT */
assert(emit_sz != 0);
if (vinfo->attrib[i].emit == EMIT_1F_PSIZE) {
src_buffer = 1;
src_offset = 0;
} else if (vinfo->attrib[i].src_index == DRAW_ATTR_NONEXIST) {
/* elements which don't exist will get assigned zeros */
src_buffer = 2;
src_offset = 0;
}
hw_key.element[i].type = TRANSLATE_ELEMENT_NORMAL;
hw_key.element[i].input_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
hw_key.element[i].input_buffer = src_buffer;
hw_key.element[i].input_offset = src_offset;
hw_key.element[i].instance_divisor = 0;
hw_key.element[i].output_format = output_format;
hw_key.element[i].output_offset = dst_offset;
dst_offset += emit_sz;
}
hw_key.nr_elements = vinfo->num_attribs;
hw_key.output_stride = vinfo->size * 4;
if (!emit->translate ||
translate_key_compare(&emit->translate->key, &hw_key) != 0) {
translate_key_sanitize(&hw_key);
emit->translate = translate_cache_find(emit->cache, &hw_key);
emit->translate->set_buffer(emit->translate, 2, &emit->zero4[0], 0, ~0);
}
if (!vinfo->size)
*max_vertices = 0;
else
*max_vertices = (draw->render->max_vertex_buffer_bytes /
(vinfo->size * 4));
}
void
draw_pt_emit(struct pt_emit *emit,
const struct draw_vertex_info *vert_info,
const struct draw_prim_info *prim_info)
{
const float (*vertex_data)[4] = (const float (*)[4])vert_info->verts->data;
unsigned vertex_count = vert_info->count;
unsigned stride = vert_info->stride;
const uint16_t *elts = prim_info->elts;
struct draw_context *draw = emit->draw;
struct translate *translate = emit->translate;
struct vbuf_render *render = draw->render;
unsigned start, i;
void *hw_verts;
/* XXX: need to flush to get prim_vbuf.c to release its allocation??
*/
draw_do_flush(draw, DRAW_FLUSH_BACKEND);
if (vertex_count == 0)
return;
/* XXX: and work out some way to coordinate the render primitive
* between vbuf.c and here...
*/
render->set_primitive(draw->render, prim_info->prim);
if (draw->render->set_view_index)
draw->render->set_view_index(draw->render, draw->pt.user.viewid);
assert(vertex_count <= 65535);
render->allocate_vertices(render,
(uint16_t)translate->key.output_stride,
(uint16_t)vertex_count);
hw_verts = render->map_vertices(render);
if (!hw_verts) {
debug_warn_once("map of vertex buffer failed (out of memory?)");
return;
}
translate->set_buffer(translate,
0,
vertex_data,
stride,
~0);
translate->set_buffer(translate,
1,
&draw->rasterizer->point_size,
0,
~0);
/* fetch/translate vertex attribs to fill hw_verts[] */
translate->run(translate,
0,
vertex_count,
0,
0,
hw_verts);
if (0) {
for (unsigned i = 0; i < vertex_count; i++) {
debug_printf("\n\n%s vertex %d:\n", __func__, i);
draw_dump_emitted_vertex(emit->vinfo,
(const uint8_t *)hw_verts +
translate->key.output_stride * i);
}
}
render->unmap_vertices(render, 0, vertex_count - 1);
for (start = i = 0;
i < prim_info->primitive_count;
start += prim_info->primitive_lengths[i], i++) {
render->draw_elements(render,
elts + start,
prim_info->primitive_lengths[i]);
}
render->release_vertices(render);
}
void
draw_pt_emit_linear(struct pt_emit *emit,
const struct draw_vertex_info *vert_info,
const struct draw_prim_info *prim_info)
{
const float (*vertex_data)[4] = (const float (*)[4])vert_info->verts->data;
unsigned stride = vert_info->stride;
unsigned count = vert_info->count;
struct draw_context *draw = emit->draw;
struct translate *translate = emit->translate;
struct vbuf_render *render = draw->render;
void *hw_verts;
unsigned start, i;
#if 0
debug_printf("Linear emit\n");
#endif
/* XXX: need to flush to get prim_vbuf.c to release its allocation??
*/
draw_do_flush(draw, DRAW_FLUSH_BACKEND);
/* XXX: and work out some way to coordinate the render primitive
* between vbuf.c and here...
*/
render->set_primitive(draw->render, prim_info->prim);
if (draw->render->set_view_index)
draw->render->set_view_index(draw->render, draw->pt.user.viewid);
assert(count <= 65535);
if (!render->allocate_vertices(render,
(uint16_t)translate->key.output_stride,
(uint16_t)count))
goto fail;
hw_verts = render->map_vertices(render);
if (!hw_verts)
goto fail;
translate->set_buffer(translate, 0,
vertex_data, stride, count - 1);
translate->set_buffer(translate, 1,
&draw->rasterizer->point_size,
0, ~0);
translate->run(translate,
0,
count,
0,
0,
hw_verts);
if (0) {
for (unsigned i = 0; i < count; i++) {
debug_printf("\n\n%s vertex %d:\n", __func__, i);
draw_dump_emitted_vertex(emit->vinfo,
(const uint8_t *)hw_verts +
translate->key.output_stride * i);
}
}
render->unmap_vertices(render, 0, count - 1);
for (start = i = 0;
i < prim_info->primitive_count;
start += prim_info->primitive_lengths[i], i++) {
render->draw_arrays(render,
start,
prim_info->primitive_lengths[i]);
}
render->release_vertices(render);
return;
fail:
debug_warn_once("allocate or map of vertex buffer failed (out of memory?)");
return;
}
struct pt_emit *
draw_pt_emit_create(struct draw_context *draw)
{
struct pt_emit *emit = CALLOC_STRUCT(pt_emit);
if (!emit)
return NULL;
emit->draw = draw;
emit->cache = translate_cache_create();
if (!emit->cache) {
FREE(emit);
return NULL;
}
emit->zero4[0] = emit->zero4[1] = emit->zero4[2] = emit->zero4[3] = 0.0f;
return emit;
}
void
draw_pt_emit_destroy(struct pt_emit *emit)
{
if (emit->cache)
translate_cache_destroy(emit->cache);
FREE(emit);
}
+219
View File
@@ -0,0 +1,219 @@
/**************************************************************************
*
* Copyright 2008 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 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 ITS 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 "util/u_memory.h"
#include "util/u_math.h"
#include "util/format/u_format.h"
#include "draw/draw_context.h"
#include "draw/draw_private.h"
#include "draw/draw_pt.h"
#include "translate/translate.h"
#include "translate/translate_cache.h"
struct pt_fetch {
struct draw_context *draw;
struct translate *translate;
unsigned vertex_size;
struct translate_cache *cache;
};
/**
* Perform the fetch from API vertex elements & vertex buffers, to a
* contiguous set of float[4] attributes as required for the
* vertex_shader->run_linear() method.
*/
void
draw_pt_fetch_prepare(struct pt_fetch *fetch,
unsigned vs_input_count,
unsigned vertex_size,
unsigned instance_id_index)
{
struct draw_context *draw = fetch->draw;
unsigned nr_inputs;
unsigned nr = 0, ei = 0;
unsigned dst_offset = 0;
unsigned num_extra_inputs = 0;
struct translate_key key;
fetch->vertex_size = vertex_size;
/* Leave the clipmask/edgeflags/pad/vertex_id,
* clip[] and whatever else in the header untouched.
*/
dst_offset = offsetof(struct vertex_header, data);
if (instance_id_index != ~0) {
num_extra_inputs++;
}
assert(draw->pt.nr_vertex_elements + num_extra_inputs >= vs_input_count);
nr_inputs = MIN2(vs_input_count, draw->pt.nr_vertex_elements + num_extra_inputs);
for (unsigned i = 0; i < nr_inputs; i++) {
if (i == instance_id_index) {
key.element[nr].type = TRANSLATE_ELEMENT_INSTANCE_ID;
key.element[nr].input_format = PIPE_FORMAT_R32_USCALED;
key.element[nr].output_format = PIPE_FORMAT_R32_USCALED;
key.element[nr].output_offset = dst_offset;
dst_offset += sizeof(uint32_t);
} else if (util_format_is_pure_sint(draw->pt.vertex_element[i].src_format)) {
key.element[nr].type = TRANSLATE_ELEMENT_NORMAL;
key.element[nr].input_format = draw->pt.vertex_element[ei].src_format;
key.element[nr].input_buffer = draw->pt.vertex_element[ei].vertex_buffer_index;
key.element[nr].input_offset = draw->pt.vertex_element[ei].src_offset;
key.element[nr].instance_divisor = draw->pt.vertex_element[ei].instance_divisor;
key.element[nr].output_format = PIPE_FORMAT_R32G32B32A32_SINT;
key.element[nr].output_offset = dst_offset;
ei++;
dst_offset += 4 * sizeof(int32_t);
} else if (util_format_is_pure_uint(draw->pt.vertex_element[i].src_format)) {
key.element[nr].type = TRANSLATE_ELEMENT_NORMAL;
key.element[nr].input_format = draw->pt.vertex_element[ei].src_format;
key.element[nr].input_buffer = draw->pt.vertex_element[ei].vertex_buffer_index;
key.element[nr].input_offset = draw->pt.vertex_element[ei].src_offset;
key.element[nr].instance_divisor = draw->pt.vertex_element[ei].instance_divisor;
key.element[nr].output_format = PIPE_FORMAT_R32G32B32A32_UINT;
key.element[nr].output_offset = dst_offset;
ei++;
dst_offset += 4 * sizeof(uint32_t);
} else {
key.element[nr].type = TRANSLATE_ELEMENT_NORMAL;
key.element[nr].input_format = draw->pt.vertex_element[ei].src_format;
key.element[nr].input_buffer = draw->pt.vertex_element[ei].vertex_buffer_index;
key.element[nr].input_offset = draw->pt.vertex_element[ei].src_offset;
key.element[nr].instance_divisor = draw->pt.vertex_element[ei].instance_divisor;
key.element[nr].output_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
key.element[nr].output_offset = dst_offset;
ei++;
dst_offset += 4 * sizeof(float);
}
nr++;
}
assert(dst_offset <= vertex_size);
key.nr_elements = nr;
key.output_stride = vertex_size;
if (!fetch->translate ||
translate_key_compare(&fetch->translate->key, &key) != 0) {
translate_key_sanitize(&key);
fetch->translate = translate_cache_find(fetch->cache, &key);
}
}
void
draw_pt_fetch_run(struct pt_fetch *fetch,
const unsigned *elts,
unsigned count,
char *verts)
{
struct draw_context *draw = fetch->draw;
struct translate *translate = fetch->translate;
for (unsigned i = 0; i < draw->pt.nr_vertex_buffers; i++) {
translate->set_buffer(translate,
i,
((char *)draw->pt.user.vbuffer[i].map +
draw->pt.vertex_buffer[i].buffer_offset),
draw->pt.vertex_strides[i],
draw->pt.max_index);
}
translate->run_elts(translate,
elts,
count,
draw->start_instance,
draw->instance_id,
verts);
}
void
draw_pt_fetch_run_linear(struct pt_fetch *fetch,
unsigned start,
unsigned count,
char *verts)
{
struct draw_context *draw = fetch->draw;
struct translate *translate = fetch->translate;
for (unsigned i = 0; i < draw->pt.nr_vertex_buffers; i++) {
translate->set_buffer(translate,
i,
((char *)draw->pt.user.vbuffer[i].map +
draw->pt.vertex_buffer[i].buffer_offset),
draw->pt.vertex_strides[i],
draw->pt.max_index);
}
translate->run(translate,
start,
count,
draw->start_instance,
draw->instance_id,
verts);
}
struct pt_fetch *
draw_pt_fetch_create(struct draw_context *draw)
{
struct pt_fetch *fetch = CALLOC_STRUCT(pt_fetch);
if (!fetch)
return NULL;
fetch->draw = draw;
fetch->cache = translate_cache_create();
if (!fetch->cache) {
FREE(fetch);
return NULL;
}
return fetch;
}
void
draw_pt_fetch_destroy(struct pt_fetch *fetch)
{
if (fetch->cache)
translate_cache_destroy(fetch->cache);
FREE(fetch);
}
@@ -0,0 +1,366 @@
/**************************************************************************
*
* Copyright 2007 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 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 ITS 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.
*
**************************************************************************/
/*
* Authors:
* Keith Whitwell <[email protected]>
*/
#include "util/u_math.h"
#include "util/u_memory.h"
#include "draw/draw_context.h"
#include "draw/draw_private.h"
#include "draw/draw_vbuf.h"
#include "draw/draw_vertex.h"
#include "draw/draw_pt.h"
#include "draw/draw_vs.h"
struct fetch_shade_emit;
/* Prototype fetch, shade, emit-hw-verts all in one go.
*/
struct fetch_shade_emit {
struct draw_pt_middle_end base;
struct draw_context *draw;
/* Temporaries:
*/
const float *constants;
unsigned pitch[PIPE_MAX_ATTRIBS];
const uint8_t *src[PIPE_MAX_ATTRIBS];
unsigned prim;
struct draw_vs_variant_key key;
struct draw_vs_variant *active;
const struct vertex_info *vinfo;
};
static void
fse_prepare(struct draw_pt_middle_end *middle,
enum mesa_prim prim,
unsigned opt,
unsigned *max_vertices)
{
struct fetch_shade_emit *fse = (struct fetch_shade_emit *)middle;
struct draw_context *draw = fse->draw;
unsigned num_vs_inputs = draw->vs.vertex_shader->info.num_inputs;
const struct vertex_info *vinfo;
unsigned nr_vbs = 0;
/* Can't support geometry shader on this path.
*/
assert(!draw->gs.geometry_shader);
draw->render->set_primitive(draw->render, prim);
/* Must do this after set_primitive() above:
*/
fse->vinfo = vinfo = draw->render->get_vertex_info(draw->render);
fse->key.output_stride = vinfo->size * 4;
fse->key.nr_outputs = vinfo->num_attribs;
fse->key.nr_inputs = num_vs_inputs;
fse->key.nr_elements = MAX2(fse->key.nr_outputs, /* outputs - translate to hw format */
fse->key.nr_inputs); /* inputs - fetch from api format */
fse->key.viewport = !draw->bypass_viewport;
fse->key.clip = draw->clip_xy || draw->clip_z || draw->clip_user;
fse->key.const_vbuffers = 0;
memset(fse->key.element, 0,
fse->key.nr_elements * sizeof(fse->key.element[0]));
for (unsigned i = 0; i < num_vs_inputs; i++) {
const struct pipe_vertex_element *src = &draw->pt.vertex_element[i];
fse->key.element[i].in.format = src->src_format;
/* Consider ignoring these, ie make generated programs
* independent of this state:
*/
fse->key.element[i].in.buffer = src->vertex_buffer_index;
fse->key.element[i].in.offset = src->src_offset;
if (src->src_stride == 0)
fse->key.const_vbuffers |= (1<<src->vertex_buffer_index);
nr_vbs = MAX2(nr_vbs, src->vertex_buffer_index + 1);
}
if (0) debug_printf("%s: lookup const_vbuffers: %x\n",
__func__, fse->key.const_vbuffers);
{
unsigned dst_offset = 0;
for (unsigned i = 0; i < vinfo->num_attribs; i++) {
unsigned emit_sz = draw_translate_vinfo_size(vinfo->attrib[i].emit);
/* doesn't handle EMIT_OMIT */
assert(emit_sz != 0);
/* The elements in the key correspond to vertex shader output
* numbers, not to positions in the hw vertex description --
* that's handled by the output_offset field.
*/
fse->key.element[i].out.format = vinfo->attrib[i].emit;
fse->key.element[i].out.vs_output = vinfo->attrib[i].src_index;
fse->key.element[i].out.offset = dst_offset;
dst_offset += emit_sz;
assert(fse->key.output_stride >= dst_offset);
}
}
fse->active = draw_vs_lookup_variant(draw->vs.vertex_shader, &fse->key);
if (!fse->active) {
assert(0);
return ;
}
if (0) debug_printf("%s: found const_vbuffers: %x\n", __func__,
fse->active->key.const_vbuffers);
/* Now set buffer pointers:
*/
for (unsigned i = 0; i < draw->pt.nr_vertex_buffers; i++) {
fse->active->set_buffer(fse->active,
i,
((const uint8_t *) draw->pt.user.vbuffer[i].map +
draw->pt.vertex_buffer[i].buffer_offset),
draw->pt.vertex_strides[i],
draw->pt.max_index);
}
*max_vertices = (draw->render->max_vertex_buffer_bytes /
(vinfo->size * 4));
/* Probably need to do this somewhere (or fix exec shader not to
* need it):
*/
if (1) {
struct draw_vertex_shader *vs = draw->vs.vertex_shader;
vs->prepare(vs, draw);
}
}
static void
fse_bind_parameters(struct draw_pt_middle_end *middle)
{
/* No-op? */
}
static void
fse_run_linear(struct draw_pt_middle_end *middle,
unsigned start,
unsigned count,
unsigned prim_flags)
{
struct fetch_shade_emit *fse = (struct fetch_shade_emit *)middle;
struct draw_context *draw = fse->draw;
char *hw_verts;
/* XXX: need to flush to get prim_vbuf.c to release its allocation??
*/
draw_do_flush(draw, DRAW_FLUSH_BACKEND);
if (!draw->render->allocate_vertices(draw->render,
(uint16_t) fse->key.output_stride,
(uint16_t) count))
goto fail;
hw_verts = draw->render->map_vertices(draw->render);
if (!hw_verts)
goto fail;
/* Single routine to fetch vertices, run shader and emit HW verts.
* Clipping is done elsewhere -- either by the API or on hardware,
* or for some other reason not required...
*/
fse->active->run_linear(fse->active, start, count, hw_verts);
if (0) {
for (unsigned i = 0; i < count; i++) {
debug_printf("\n\n%s vertex %d: (stride %d, offset %d)\n",
__func__, i,
fse->key.output_stride,
fse->key.output_stride * i);
draw_dump_emitted_vertex(fse->vinfo,
(const uint8_t *) hw_verts
+ fse->key.output_stride * i);
}
}
draw->render->unmap_vertices(draw->render, 0, (uint16_t) (count - 1));
/* Draw arrays path to avoid re-emitting index list again and
* again.
*/
draw->render->draw_arrays(draw->render, 0, count);
draw->render->release_vertices(draw->render);
return;
fail:
debug_warn_once("allocate or map of vertex buffer failed (out of memory?)");
return;
}
static void
fse_run(struct draw_pt_middle_end *middle,
unsigned start,
const unsigned *fetch_elts,
unsigned fetch_count,
const uint16_t *draw_elts,
unsigned draw_count,
unsigned prim_flags)
{
struct fetch_shade_emit *fse = (struct fetch_shade_emit *)middle;
struct draw_context *draw = fse->draw;
void *hw_verts;
/* XXX: need to flush to get prim_vbuf.c to release its allocation??
*/
draw_do_flush(draw, DRAW_FLUSH_BACKEND);
if (!draw->render->allocate_vertices(draw->render,
(uint16_t) fse->key.output_stride,
(uint16_t) fetch_count))
goto fail;
hw_verts = draw->render->map_vertices(draw->render);
if (!hw_verts)
goto fail;
/* Single routine to fetch vertices, run shader and emit HW verts.
*/
fse->active->run_elts(fse->active, fetch_elts, fetch_count, hw_verts);
if (0) {
for (unsigned i = 0; i < fetch_count; i++) {
debug_printf("\n\n%s vertex %d:\n", __func__, i);
draw_dump_emitted_vertex(fse->vinfo,
(const uint8_t *)hw_verts +
fse->key.output_stride * i);
}
}
draw->render->unmap_vertices(draw->render, 0, (uint16_t)(fetch_count - 1));
draw->render->draw_elements(draw->render, draw_elts, draw_count);
draw->render->release_vertices(draw->render);
return;
fail:
debug_warn_once("allocate or map of vertex buffer failed (out of memory?)");
return;
}
static bool
fse_run_linear_elts(struct draw_pt_middle_end *middle,
unsigned start,
unsigned count,
const uint16_t *draw_elts,
unsigned draw_start,
unsigned draw_count)
{
struct fetch_shade_emit *fse = (struct fetch_shade_emit *)middle;
struct draw_context *draw = fse->draw;
char *hw_verts;
/* XXX: need to flush to get prim_vbuf.c to release its allocation??
*/
draw_do_flush(draw, DRAW_FLUSH_BACKEND);
if (!draw->render->allocate_vertices(draw->render,
(uint16_t) fse->key.output_stride,
(uint16_t) count))
return false;
hw_verts = draw->render->map_vertices(draw->render);
if (!hw_verts)
return false;
/* Single routine to fetch vertices, run shader and emit HW verts.
* Clipping is done elsewhere -- either by the API or on hardware,
* or for some other reason not required...
*/
fse->active->run_linear(fse->active, start, count, hw_verts);
draw->render->draw_elements(draw->render, draw_elts, draw_count);
draw->render->unmap_vertices(draw->render, 0, (uint16_t)(count - 1));
draw->render->release_vertices(draw->render);
return true;
}
static void
fse_finish(struct draw_pt_middle_end *middle)
{
}
static void
fse_destroy(struct draw_pt_middle_end *middle)
{
FREE(middle);
}
struct draw_pt_middle_end *
draw_pt_middle_fse(struct draw_context *draw)
{
struct fetch_shade_emit *fse = CALLOC_STRUCT(fetch_shade_emit);
if (!fse)
return NULL;
fse->base.prepare = fse_prepare;
fse->base.bind_parameters = fse_bind_parameters;
fse->base.run = fse_run;
fse->base.run_linear = fse_run_linear;
fse->base.run_linear_elts = fse_run_linear_elts;
fse->base.finish = fse_finish;
fse->base.destroy = fse_destroy;
fse->draw = draw;
return &fse->base;
}
@@ -0,0 +1,552 @@
/**************************************************************************
*
* Copyright 2007 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 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 ITS 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 "util/u_math.h"
#include "util/u_memory.h"
#include "util/u_prim.h"
#include "draw/draw_context.h"
#include "draw/draw_vbuf.h"
#include "draw/draw_vertex.h"
#include "draw/draw_prim_assembler.h"
#include "draw/draw_pt.h"
#include "draw/draw_vs.h"
#include "draw/draw_gs.h"
struct fetch_pipeline_middle_end {
struct draw_pt_middle_end base;
struct draw_context *draw;
struct pt_emit *emit;
struct pt_so_emit *so_emit;
struct pt_fetch *fetch;
struct pt_post_vs *post_vs;
unsigned vertex_data_offset;
unsigned vertex_size;
unsigned input_prim;
unsigned opt;
};
/** cast wrapper */
static inline struct fetch_pipeline_middle_end *
fetch_pipeline_middle_end(struct draw_pt_middle_end *middle)
{
return (struct fetch_pipeline_middle_end *) middle;
}
/**
* Prepare/validate middle part of the vertex pipeline.
* NOTE: if you change this function, also look at the LLVM
* function llvm_middle_end_prepare() for similar changes.
*/
static void
fetch_pipeline_prepare(struct draw_pt_middle_end *middle,
enum mesa_prim prim,
unsigned opt,
unsigned *max_vertices)
{
struct fetch_pipeline_middle_end *fpme = fetch_pipeline_middle_end(middle);
struct draw_context *draw = fpme->draw;
struct draw_vertex_shader *vs = draw->vs.vertex_shader;
struct draw_geometry_shader *gs = draw->gs.geometry_shader;
unsigned instance_id_index = ~0;
const unsigned gs_out_prim = (gs ? gs->output_primitive :
u_assembled_prim(prim));
unsigned nr_vs_outputs = draw_total_vs_outputs(draw);
unsigned nr = MAX2(vs->info.num_inputs, nr_vs_outputs);
unsigned point_line_clip = draw->rasterizer->fill_front == PIPE_POLYGON_MODE_POINT ||
draw->rasterizer->fill_front == PIPE_POLYGON_MODE_LINE ||
gs_out_prim == MESA_PRIM_POINTS ||
gs_out_prim == MESA_PRIM_LINE_STRIP;
if (gs) {
nr = MAX2(nr, gs->info.num_outputs + 1);
}
/* Scan for instanceID system value.
*/
for (unsigned i = 0; i < vs->info.num_inputs; i++) {
if (vs->info.input_semantic_name[i] == TGSI_SEMANTIC_INSTANCEID) {
instance_id_index = i;
break;
}
}
fpme->input_prim = prim;
fpme->opt = opt;
/* Always leave room for the vertex header whether we need it or
* not. It's hard to get rid of it in particular because of the
* viewport code in draw_pt_post_vs.c.
*/
fpme->vertex_size = sizeof(struct vertex_header) + nr * 4 * sizeof(float);
draw_pt_fetch_prepare(fpme->fetch,
vs->info.num_inputs,
fpme->vertex_size,
instance_id_index);
draw_pt_post_vs_prepare(fpme->post_vs,
draw->clip_xy,
draw->clip_z,
draw->clip_user,
point_line_clip ? draw->guard_band_points_lines_xy :
draw->guard_band_xy,
draw->bypass_viewport,
draw->rasterizer->clip_halfz,
(draw->vs.edgeflag_output ? true : false));
draw_pt_so_emit_prepare(fpme->so_emit, false);
if (!(opt & PT_PIPELINE)) {
draw_pt_emit_prepare(fpme->emit, gs_out_prim, max_vertices);
*max_vertices = MAX2(*max_vertices, 4096);
}
else {
/* limit max fetches by limiting max_vertices */
*max_vertices = 4096;
}
/* No need to prepare the shader.
*/
vs->prepare(vs, draw);
/* Make sure that the vertex size didn't change at any point above */
assert(nr_vs_outputs == draw_total_vs_outputs(draw));
}
static void
fetch_pipeline_bind_parameters(struct draw_pt_middle_end *middle)
{
/* No-op since the vertex shader executor and drawing pipeline
* just grab the constants, viewport, etc. from the draw context state.
*/
}
static void
fetch(struct pt_fetch *fetch,
const struct draw_fetch_info *fetch_info,
char *output)
{
if (fetch_info->linear) {
draw_pt_fetch_run_linear(fetch, fetch_info->start,
fetch_info->count, output);
}
else {
draw_pt_fetch_run(fetch, fetch_info->elts, fetch_info->count, output);
}
}
static void
pipeline(struct fetch_pipeline_middle_end *fpme,
const struct draw_vertex_info *vert_info,
const struct draw_prim_info *prim_info)
{
if (prim_info->linear)
draw_pipeline_run_linear(fpme->draw, vert_info, prim_info);
else
draw_pipeline_run(fpme->draw, vert_info, prim_info);
}
static void
emit(struct pt_emit *emit,
const struct draw_vertex_info *vert_info,
const struct draw_prim_info *prim_info)
{
if (prim_info->linear) {
draw_pt_emit_linear(emit, vert_info, prim_info);
}
else {
draw_pt_emit(emit, vert_info, prim_info);
}
}
static void
draw_vertex_shader_run(struct draw_vertex_shader *vshader,
const struct draw_buffer_info *constants,
const struct draw_fetch_info *fetch_info,
const struct draw_vertex_info *input_verts,
struct draw_vertex_info *output_verts)
{
output_verts->vertex_size = input_verts->vertex_size;
output_verts->stride = input_verts->vertex_size;
output_verts->count = input_verts->count;
output_verts->verts =
(struct vertex_header *)MALLOC(output_verts->vertex_size *
align(output_verts->count, 4) +
DRAW_EXTRA_VERTICES_PADDING);
vshader->run_linear(vshader,
(const float (*)[4])input_verts->verts->data,
( float (*)[4])output_verts->verts->data,
constants,
input_verts->count,
input_verts->vertex_size,
input_verts->vertex_size,
fetch_info->elts);
}
static void
fetch_pipeline_generic(struct draw_pt_middle_end *middle,
const struct draw_fetch_info *fetch_info,
const struct draw_prim_info *in_prim_info)
{
struct fetch_pipeline_middle_end *fpme = fetch_pipeline_middle_end(middle);
struct draw_context *draw = fpme->draw;
struct draw_vertex_shader *vshader = draw->vs.vertex_shader;
struct draw_geometry_shader *gshader = draw->gs.geometry_shader;
struct draw_prim_info gs_prim_info[TGSI_MAX_VERTEX_STREAMS];
struct draw_vertex_info fetched_vert_info;
struct draw_vertex_info vs_vert_info;
struct draw_vertex_info gs_vert_info[TGSI_MAX_VERTEX_STREAMS];
struct draw_vertex_info *vert_info;
struct draw_prim_info ia_prim_info;
struct draw_vertex_info ia_vert_info;
const struct draw_prim_info *prim_info = in_prim_info;
bool free_prim_info = false;
unsigned opt = fpme->opt;
int num_vertex_streams = 1;
fetched_vert_info.count = fetch_info->count;
fetched_vert_info.vertex_size = fpme->vertex_size;
fetched_vert_info.stride = fpme->vertex_size;
fetched_vert_info.verts =
(struct vertex_header *)MALLOC(fpme->vertex_size *
align(fetch_info->count, 4) +
DRAW_EXTRA_VERTICES_PADDING);
if (!fetched_vert_info.verts) {
assert(0);
return;
}
if (draw->collect_statistics) {
draw->statistics.ia_vertices += prim_info->count;
draw->statistics.ia_primitives +=
u_decomposed_prims_for_vertices(prim_info->prim, fetch_info->count);
draw->statistics.vs_invocations += fetch_info->count;
}
/* Fetch into our vertex buffer.
*/
fetch(fpme->fetch, fetch_info, (char *)fetched_vert_info.verts);
vert_info = &fetched_vert_info;
/* Run the shader, note that this overwrites the data[] parts of
* the pipeline verts.
* Need fetch info to get vertex id correct.
*/
if (fpme->opt & PT_SHADE) {
draw_vertex_shader_run(vshader,
draw->pt.user.constants[MESA_SHADER_VERTEX],
fetch_info,
vert_info,
&vs_vert_info);
FREE(vert_info->verts);
vert_info = &vs_vert_info;
}
/* Finished with fetch:
*/
fetch_info = NULL;
if ((fpme->opt & PT_SHADE) && gshader) {
draw_geometry_shader_run(gshader,
draw->pt.user.constants[MESA_SHADER_GEOMETRY],
vert_info,
prim_info,
&vshader->info,
NULL,
gs_vert_info,
gs_prim_info);
FREE(vert_info->verts);
vert_info = &gs_vert_info[0];
prim_info = &gs_prim_info[0];
num_vertex_streams = gshader->num_vertex_streams;
/*
* pt emit can only handle ushort number of vertices (see
* render->allocate_vertices).
* vsplit guarantees there's never more than 4096, however GS can
* easily blow this up (by a factor of 256 (or even 1024) max).
*/
if (vert_info->count > 65535) {
opt |= PT_PIPELINE;
}
} else {
if (draw_prim_assembler_is_required(draw, prim_info, vert_info)) {
draw_prim_assembler_run(draw, prim_info, vert_info,
&ia_prim_info, &ia_vert_info);
if (ia_vert_info.count) {
FREE(vert_info->verts);
vert_info = &ia_vert_info;
prim_info = &ia_prim_info;
free_prim_info = true;
}
}
}
if (prim_info->count == 0) {
// debug_printf("GS/IA didn't emit any vertices!\n");
FREE(vert_info->verts);
if (free_prim_info) {
FREE(prim_info->primitive_lengths);
}
return;
}
/* Stream output needs to be done before clipping.
*
* XXX: Stream output surely needs to respect the prim_info->elt
* lists.
*/
draw_pt_so_emit(fpme->so_emit, num_vertex_streams, vert_info, prim_info);
/* rasterization stream selection */
if ((fpme->opt & PT_SHADE) && gshader) {
unsigned rs = draw->rasterizer->rasterization_stream;
if (rs < gshader->num_vertex_streams) {
vert_info = &gs_vert_info[rs];
prim_info = &gs_prim_info[rs];
}
}
draw_stats_clipper_primitives(draw, prim_info);
/*
* if there's no position, need to stop now, or the latter stages
* will try to access non-existent position output.
*/
if (draw_current_shader_position_output(draw) != -1) {
if (draw_pt_post_vs_run(fpme->post_vs, vert_info, prim_info)) {
opt |= PT_PIPELINE;
}
/* Do we need to run the pipeline?
*/
if (opt & PT_PIPELINE) {
pipeline(fpme, vert_info, prim_info);
}
else {
emit(fpme->emit, vert_info, prim_info);
}
}
if ((fpme->opt & PT_SHADE) && gshader) {
for (unsigned i = 0; i < gshader->num_vertex_streams; i++)
FREE(gs_vert_info[i].verts);
} else {
FREE(vert_info->verts);
}
if (free_prim_info) {
FREE(prim_info->primitive_lengths);
}
}
static inline unsigned
prim_type(unsigned prim, unsigned flags)
{
if (flags & DRAW_LINE_LOOP_AS_STRIP)
return MESA_PRIM_LINE_STRIP;
else
return prim;
}
static void
fetch_pipeline_run(struct draw_pt_middle_end *middle,
unsigned start,
const unsigned *fetch_elts,
unsigned fetch_count,
const uint16_t *draw_elts,
unsigned draw_count,
unsigned prim_flags)
{
struct fetch_pipeline_middle_end *fpme = fetch_pipeline_middle_end(middle);
struct draw_fetch_info fetch_info;
struct draw_prim_info prim_info;
fetch_info.linear = false;
fetch_info.start = start;
fetch_info.elts = fetch_elts;
fetch_info.count = fetch_count;
prim_info.linear = false;
prim_info.start = start - fpme->draw->start_index;
prim_info.count = draw_count;
prim_info.elts = draw_elts;
prim_info.prim = prim_type(fpme->input_prim, prim_flags);
prim_info.flags = prim_flags;
prim_info.primitive_count = 1;
prim_info.primitive_lengths = &draw_count;
fetch_pipeline_generic(middle, &fetch_info, &prim_info);
}
static void
fetch_pipeline_linear_run(struct draw_pt_middle_end *middle,
unsigned start,
unsigned count,
unsigned prim_flags)
{
struct fetch_pipeline_middle_end *fpme = fetch_pipeline_middle_end(middle);
struct draw_fetch_info fetch_info;
struct draw_prim_info prim_info;
fetch_info.linear = true;
fetch_info.start = start;
fetch_info.count = count;
fetch_info.elts = NULL;
prim_info.linear = true;
prim_info.start = start - fpme->draw->start_index;
prim_info.count = count;
prim_info.elts = NULL;
prim_info.prim = prim_type(fpme->input_prim, prim_flags);
prim_info.flags = prim_flags;
prim_info.primitive_count = 1;
prim_info.primitive_lengths = &count;
fetch_pipeline_generic(middle, &fetch_info, &prim_info);
}
static bool
fetch_pipeline_linear_run_elts(struct draw_pt_middle_end *middle,
unsigned start,
unsigned count,
const uint16_t *draw_elts,
unsigned draw_start,
unsigned draw_count)
{
struct fetch_pipeline_middle_end *fpme = fetch_pipeline_middle_end(middle);
struct draw_fetch_info fetch_info;
struct draw_prim_info prim_info;
fetch_info.linear = true;
fetch_info.start = start;
fetch_info.count = count;
fetch_info.elts = NULL;
prim_info.linear = false;
prim_info.start = draw_start - fpme->draw->start_index;
prim_info.count = draw_count;
prim_info.elts = draw_elts;
prim_info.prim = fpme->input_prim;
prim_info.flags = 0;
prim_info.primitive_count = 1;
prim_info.primitive_lengths = &draw_count;
fetch_pipeline_generic(middle, &fetch_info, &prim_info);
return true;
}
static void
fetch_pipeline_finish(struct draw_pt_middle_end *middle)
{
/* nothing to do */
}
static void
fetch_pipeline_destroy(struct draw_pt_middle_end *middle)
{
struct fetch_pipeline_middle_end *fpme = fetch_pipeline_middle_end(middle);
if (fpme->fetch)
draw_pt_fetch_destroy(fpme->fetch);
if (fpme->emit)
draw_pt_emit_destroy(fpme->emit);
if (fpme->so_emit)
draw_pt_so_emit_destroy(fpme->so_emit);
if (fpme->post_vs)
draw_pt_post_vs_destroy(fpme->post_vs);
FREE(middle);
}
struct draw_pt_middle_end *
draw_pt_fetch_pipeline_or_emit(struct draw_context *draw)
{
struct fetch_pipeline_middle_end *fpme =
CALLOC_STRUCT(fetch_pipeline_middle_end);
if (!fpme)
goto fail;
fpme->base.prepare = fetch_pipeline_prepare;
fpme->base.bind_parameters = fetch_pipeline_bind_parameters;
fpme->base.run = fetch_pipeline_run;
fpme->base.run_linear = fetch_pipeline_linear_run;
fpme->base.run_linear_elts = fetch_pipeline_linear_run_elts;
fpme->base.finish = fetch_pipeline_finish;
fpme->base.destroy = fetch_pipeline_destroy;
fpme->draw = draw;
fpme->fetch = draw_pt_fetch_create(draw);
if (!fpme->fetch)
goto fail;
fpme->post_vs = draw_pt_post_vs_create(draw);
if (!fpme->post_vs)
goto fail;
fpme->emit = draw_pt_emit_create(draw);
if (!fpme->emit)
goto fail;
fpme->so_emit = draw_pt_so_emit_create(draw);
if (!fpme->so_emit)
goto fail;
return &fpme->base;
fail:
if (fpme)
fetch_pipeline_destroy(&fpme->base);
return NULL;
}
@@ -0,0 +1,931 @@
/**************************************************************************
*
* Copyright 2010 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 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 ITS 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 "util/u_math.h"
#include "util/u_memory.h"
#include "util/u_prim.h"
#include "draw/draw_context.h"
#include "draw/draw_gs.h"
#include "draw/draw_tess.h"
#include "draw/draw_vbuf.h"
#include "draw/draw_vertex.h"
#include "draw/draw_pt.h"
#include "draw/draw_prim_assembler.h"
#include "draw/draw_vs.h"
#include "draw/draw_llvm.h"
#include "gallivm/lp_bld_init.h"
#include "gallivm/lp_bld_debug.h"
struct llvm_middle_end {
struct draw_pt_middle_end base;
struct draw_context *draw;
struct pt_emit *emit;
struct pt_so_emit *so_emit;
struct pt_fetch *fetch;
struct pt_post_vs *post_vs;
unsigned vertex_data_offset;
unsigned vertex_size;
enum mesa_prim input_prim;
unsigned opt;
struct draw_llvm *llvm;
struct draw_llvm_variant *current_variant;
};
/** cast wrapper */
static inline struct llvm_middle_end *
llvm_middle_end(struct draw_pt_middle_end *middle)
{
return (struct llvm_middle_end *) middle;
}
static void
llvm_middle_end_prepare_gs(struct llvm_middle_end *fpme)
{
struct draw_context *draw = fpme->draw;
struct draw_llvm *llvm = fpme->llvm;
struct draw_geometry_shader *gs = draw->gs.geometry_shader;
struct draw_gs_llvm_variant_list_item *li;
struct llvm_geometry_shader *shader = llvm_geometry_shader(gs);
char store[DRAW_GS_LLVM_MAX_VARIANT_KEY_SIZE];
struct draw_gs_llvm_variant_key *key = draw_gs_llvm_make_variant_key(llvm, store);
/* Search shader's list of variants for the key */
struct draw_gs_llvm_variant *variant = NULL;
LIST_FOR_EACH_ENTRY(li, &shader->variants.list, list) {
if (memcmp(&li->base->key, key, shader->variant_key_size) == 0) {
variant = li->base;
break;
}
}
if (variant) {
/* found the variant, move to head of global list (for LRU) */
list_move_to(&variant->list_item_global.list, &llvm->gs_variants_list.list);
} else {
/* Need to create new variant */
/* First check if we've created too many variants. If so, free
* 3.125% of the LRU to avoid using too much memory.
*/
if (llvm->nr_gs_variants >= DRAW_MAX_SHADER_VARIANTS) {
if (gallivm_debug & GALLIVM_DEBUG_PERF) {
debug_printf("Evicting GS: %u gs variants,\t%u total variants\n",
shader->variants_cached, llvm->nr_gs_variants);
}
/*
* XXX: should we flush here ?
*/
struct draw_gs_llvm_variant_list_item *item;
for (unsigned i = 0; i < DRAW_MAX_SHADER_VARIANTS / 32; i++) {
if (list_is_empty(&llvm->gs_variants_list.list)) {
break;
}
item = list_last_entry(&llvm->gs_variants_list.list,
struct draw_gs_llvm_variant_list_item, list);
assert(item);
assert(item->base);
draw_gs_llvm_destroy_variant(item->base);
}
}
variant = draw_gs_llvm_create_variant(llvm, draw_total_gs_outputs(draw), key);
if (variant) {
list_add(&variant->list_item_local.list, &shader->variants.list);
list_add(&variant->list_item_global.list, &llvm->gs_variants_list.list);
llvm->nr_gs_variants++;
shader->variants_cached++;
}
}
gs->current_variant = variant;
}
static void
llvm_middle_end_prepare_tcs(struct llvm_middle_end *fpme)
{
struct draw_context *draw = fpme->draw;
struct draw_llvm *llvm = fpme->llvm;
struct draw_tess_ctrl_shader *tcs = draw->tcs.tess_ctrl_shader;
struct draw_tcs_llvm_variant_list_item *li;
struct llvm_tess_ctrl_shader *shader = llvm_tess_ctrl_shader(tcs);
char store[DRAW_TCS_LLVM_MAX_VARIANT_KEY_SIZE];
const struct draw_tcs_llvm_variant_key *key =
draw_tcs_llvm_make_variant_key(llvm, store);
/* Search shader's list of variants for the key */
struct draw_tcs_llvm_variant *variant = NULL;
LIST_FOR_EACH_ENTRY(li, &shader->variants.list, list) {
if (memcmp(&li->base->key, key, shader->variant_key_size) == 0) {
variant = li->base;
break;
}
}
if (variant) {
/* found the variant, move to head of global list (for LRU) */
list_move_to(&variant->list_item_global.list,
&llvm->tcs_variants_list.list);
} else {
/* Need to create new variant */
/* First check if we've created too many variants. If so, free
* 3.125% of the LRU to avoid using too much memory.
*/
if (llvm->nr_tcs_variants >= DRAW_MAX_SHADER_VARIANTS) {
if (gallivm_debug & GALLIVM_DEBUG_PERF) {
debug_printf("Evicting TCS: %u tcs variants,\t%u total variants\n",
shader->variants_cached, llvm->nr_tcs_variants);
}
/*
* XXX: should we flush here ?
*/
for (unsigned i = 0; i < DRAW_MAX_SHADER_VARIANTS / 32; i++) {
struct draw_tcs_llvm_variant_list_item *item;
if (list_is_empty(&llvm->tcs_variants_list.list)) {
break;
}
item = list_last_entry(&llvm->tcs_variants_list.list,
struct draw_tcs_llvm_variant_list_item, list);
assert(item);
assert(item->base);
draw_tcs_llvm_destroy_variant(item->base);
}
}
variant = draw_tcs_llvm_create_variant(llvm, 0, key);
if (variant) {
list_add(&variant->list_item_local.list, &shader->variants.list);
list_add(&variant->list_item_global.list, &llvm->tcs_variants_list.list);
llvm->nr_tcs_variants++;
shader->variants_cached++;
}
}
tcs->current_variant = variant;
}
static void
llvm_middle_end_prepare_tes(struct llvm_middle_end *fpme)
{
struct draw_context *draw = fpme->draw;
struct draw_llvm *llvm = fpme->llvm;
struct draw_tess_eval_shader *tes = draw->tes.tess_eval_shader;
struct draw_tes_llvm_variant *variant = NULL;
struct draw_tes_llvm_variant_list_item *li;
struct llvm_tess_eval_shader *shader = llvm_tess_eval_shader(tes);
char store[DRAW_TES_LLVM_MAX_VARIANT_KEY_SIZE];
const struct draw_tes_llvm_variant_key *key =
draw_tes_llvm_make_variant_key(llvm, store);
/* Search shader's list of variants for the key */
LIST_FOR_EACH_ENTRY(li, &shader->variants.list, list) {
if (memcmp(&li->base->key, key, shader->variant_key_size) == 0) {
variant = li->base;
break;
}
}
if (variant) {
/* found the variant, move to head of global list (for LRU) */
list_move_to(&variant->list_item_global.list,
&llvm->tes_variants_list.list);
} else {
/* Need to create new variant */
/* First check if we've created too many variants. If so, free
* 3.125% of the LRU to avoid using too much memory.
*/
if (llvm->nr_tes_variants >= DRAW_MAX_SHADER_VARIANTS) {
if (gallivm_debug & GALLIVM_DEBUG_PERF) {
debug_printf("Evicting TES: %u tes variants,\t%u total variants\n",
shader->variants_cached, llvm->nr_tes_variants);
}
/*
* XXX: should we flush here ?
*/
for (unsigned i = 0; i < DRAW_MAX_SHADER_VARIANTS / 32; i++) {
struct draw_tes_llvm_variant_list_item *item;
if (list_is_empty(&llvm->tes_variants_list.list)) {
break;
}
item = list_last_entry(&llvm->tes_variants_list.list,
struct draw_tes_llvm_variant_list_item, list);
assert(item);
assert(item->base);
draw_tes_llvm_destroy_variant(item->base);
}
}
variant = draw_tes_llvm_create_variant(llvm, draw_total_tes_outputs(draw), key);
if (variant) {
list_add(&variant->list_item_local.list, &shader->variants.list);
list_add(&variant->list_item_global.list, &llvm->tes_variants_list.list);
llvm->nr_tes_variants++;
shader->variants_cached++;
}
}
tes->current_variant = variant;
}
/**
* Prepare/validate middle part of the vertex pipeline.
* NOTE: if you change this function, also look at the non-LLVM
* function fetch_pipeline_prepare() for similar changes.
*/
static void
llvm_middle_end_prepare(struct draw_pt_middle_end *middle,
enum mesa_prim in_prim,
unsigned opt,
unsigned *max_vertices)
{
struct llvm_middle_end *fpme = llvm_middle_end(middle);
struct draw_context *draw = fpme->draw;
struct draw_llvm *llvm = fpme->llvm;
struct draw_vertex_shader *vs = draw->vs.vertex_shader;
struct draw_geometry_shader *gs = draw->gs.geometry_shader;
struct draw_tess_ctrl_shader *tcs = draw->tcs.tess_ctrl_shader;
struct draw_tess_eval_shader *tes = draw->tes.tess_eval_shader;
const enum mesa_prim out_prim =
gs ? gs->output_primitive : tes ? get_tes_output_prim(tes) :
u_assembled_prim(in_prim);
unsigned point_line_clip = draw->rasterizer->fill_front == PIPE_POLYGON_MODE_POINT ||
draw->rasterizer->fill_front == PIPE_POLYGON_MODE_LINE ||
out_prim == MESA_PRIM_POINTS ||
u_reduced_prim(out_prim) == MESA_PRIM_LINES;
fpme->input_prim = in_prim;
fpme->opt = opt;
draw_pt_post_vs_prepare(fpme->post_vs,
draw->clip_xy,
draw->clip_z,
draw->clip_user,
point_line_clip ? draw->guard_band_points_lines_xy :
draw->guard_band_xy,
draw->bypass_viewport,
draw->rasterizer->clip_halfz,
(draw->vs.edgeflag_output ? true : false));
draw_pt_so_emit_prepare(fpme->so_emit, (gs == NULL && tes == NULL));
if (!(opt & PT_PIPELINE)) {
draw_pt_emit_prepare(fpme->emit, out_prim, max_vertices);
*max_vertices = MAX2(*max_vertices, 4096);
} else {
/* limit max fetches by limiting max_vertices */
*max_vertices = 4096;
}
/* Get the number of float[4] attributes per vertex.
* Note: this must be done after draw_pt_emit_prepare() since that
* can effect the vertex size.
*/
unsigned nr = MAX2(vs->info.num_inputs, draw_total_vs_outputs(draw));
/* Always leave room for the vertex header whether we need it or
* not. It's hard to get rid of it in particular because of the
* viewport code in draw_pt_post_vs.c.
*/
fpme->vertex_size = sizeof(struct vertex_header) + nr * 4 * sizeof(float);
/* return even number */
*max_vertices = *max_vertices & ~1;
/* Find/create the vertex shader variant */
{
struct draw_llvm_variant *variant = NULL;
struct draw_llvm_variant_list_item *li;
struct llvm_vertex_shader *shader = llvm_vertex_shader(vs);
char store[DRAW_LLVM_MAX_VARIANT_KEY_SIZE];
struct draw_llvm_variant_key *key = draw_llvm_make_variant_key(llvm, store);
/* Search shader's list of variants for the key */
LIST_FOR_EACH_ENTRY(li, &shader->variants.list, list) {
if (memcmp(&li->base->key, key, shader->variant_key_size) == 0) {
variant = li->base;
break;
}
}
if (variant) {
/* found the variant, move to head of global list (for LRU) */
list_move_to(&variant->list_item_global.list, &llvm->vs_variants_list.list);
} else {
/* Need to create new variant */
/* First check if we've created too many variants. If so, free
* 3.125% of the LRU to avoid using too much memory.
*/
if (llvm->nr_variants >= DRAW_MAX_SHADER_VARIANTS) {
if (gallivm_debug & GALLIVM_DEBUG_PERF) {
debug_printf("Evicting VS: %u vs variants,\t%u total variants\n",
shader->variants_cached, llvm->nr_variants);
}
/*
* XXX: should we flush here ?
*/
for (unsigned i = 0; i < DRAW_MAX_SHADER_VARIANTS / 32; i++) {
struct draw_llvm_variant_list_item *item;
if (list_is_empty(&llvm->vs_variants_list.list)) {
break;
}
item = list_last_entry(&llvm->vs_variants_list.list,
struct draw_llvm_variant_list_item, list);
assert(item);
assert(item->base);
draw_llvm_destroy_variant(item->base);
}
}
variant = draw_llvm_create_variant(llvm, nr, key);
if (variant) {
list_add(&variant->list_item_local.list, &shader->variants.list);
list_add(&variant->list_item_global.list, &llvm->vs_variants_list.list);
llvm->nr_variants++;
shader->variants_cached++;
}
}
fpme->current_variant = variant;
}
if (gs) {
llvm_middle_end_prepare_gs(fpme);
}
if (tcs) {
llvm_middle_end_prepare_tcs(fpme);
}
if (tes) {
llvm_middle_end_prepare_tes(fpme);
}
}
static unsigned
get_num_consts_robust(struct draw_context *draw, struct draw_buffer_info *bufs, unsigned idx)
{
uint64_t const_bytes = bufs[idx].size;
if (const_bytes < sizeof(float))
return 0;
return DIV_ROUND_UP(const_bytes, draw->constant_buffer_stride);
}
/**
* Bind/update constant buffer pointers, clip planes and viewport dims.
* These are "light weight" parameters which aren't baked into the
* generated code. Updating these items is much cheaper than revalidating
* and rebuilding the generated pipeline code.
*/
static void
llvm_middle_end_bind_parameters(struct draw_pt_middle_end *middle)
{
static const float fake_const_buf[4];
struct llvm_middle_end *fpme = llvm_middle_end(middle);
struct draw_context *draw = fpme->draw;
struct draw_llvm *llvm = fpme->llvm;
unsigned i;
for (mesa_shader_stage shader_type = MESA_SHADER_VERTEX; shader_type <= MESA_SHADER_GEOMETRY; shader_type++) {
for (i = 0; i < ARRAY_SIZE(llvm->jit_resources[shader_type].constants); ++i) {
/*
* There could be a potential issue with rounding this up, as the
* shader expects 16-byte allocations, the fix is likely to move
* to LOAD intrinsic in the future and remove the vec4 constraint.
*/
int num_consts = get_num_consts_robust(draw, draw->pt.user.constants[shader_type], i);
llvm->jit_resources[shader_type].constants[i].f = draw->pt.user.constants[shader_type][i].ptr;
llvm->jit_resources[shader_type].constants[i].num_elements = num_consts;
if (num_consts == 0) {
llvm->jit_resources[shader_type].constants[i].f = fake_const_buf;
}
}
for (i = 0; i < ARRAY_SIZE(llvm->jit_resources[shader_type].ssbos); ++i) {
int num_ssbos = draw->pt.user.ssbos[shader_type][i].size;
llvm->jit_resources[shader_type].ssbos[i].u = draw->pt.user.ssbos[shader_type][i].ptr;
llvm->jit_resources[shader_type].ssbos[i].num_elements = num_ssbos;
if (num_ssbos == 0) {
llvm->jit_resources[shader_type].ssbos[i].u = (const uint32_t *)fake_const_buf;
}
}
}
llvm->vs_jit_context.planes =
(float (*)[DRAW_TOTAL_CLIP_PLANES][4]) draw->pt.user.planes[0];
llvm->gs_jit_context.planes =
(float (*)[DRAW_TOTAL_CLIP_PLANES][4]) draw->pt.user.planes[0];
llvm->vs_jit_context.viewports = draw->viewports;
llvm->gs_jit_context.viewports = draw->viewports;
}
static void
pipeline(struct llvm_middle_end *llvm,
const struct draw_vertex_info *vert_info,
const struct draw_prim_info *prim_info)
{
if (prim_info->linear)
draw_pipeline_run_linear(llvm->draw, vert_info, prim_info);
else
draw_pipeline_run(llvm->draw, vert_info, prim_info);
}
static void
emit(struct pt_emit *emit,
const struct draw_vertex_info *vert_info,
const struct draw_prim_info *prim_info)
{
if (prim_info->linear)
draw_pt_emit_linear(emit, vert_info, prim_info);
else
draw_pt_emit(emit, vert_info, prim_info);
}
static void
llvm_pipeline_generic(struct draw_pt_middle_end *middle,
const struct draw_fetch_info *fetch_info,
const struct draw_prim_info *in_prim_info)
{
struct llvm_middle_end *fpme = llvm_middle_end(middle);
struct draw_context *draw = fpme->draw;
struct draw_geometry_shader *gshader = draw->gs.geometry_shader;
struct draw_tess_ctrl_shader *tcs_shader = draw->tcs.tess_ctrl_shader;
struct draw_tess_eval_shader *tes_shader = draw->tes.tess_eval_shader;
struct draw_prim_info tcs_prim_info;
struct draw_prim_info tes_prim_info;
struct draw_prim_info gs_prim_info[TGSI_MAX_VERTEX_STREAMS];
struct draw_vertex_info llvm_vert_info;
struct draw_vertex_info tcs_vert_info;
struct draw_vertex_info tes_vert_info;
struct draw_vertex_info *vert_info;
struct draw_prim_info ia_prim_info;
struct draw_vertex_info ia_vert_info;
const struct draw_prim_info *prim_info = in_prim_info;
bool free_prim_info = false;
unsigned opt = fpme->opt;
bool clipped = 0;
uint16_t *tes_elts_out = NULL;
assert(fetch_info->count > 0);
llvm_vert_info.count = fetch_info->count;
llvm_vert_info.vertex_size = fpme->vertex_size;
llvm_vert_info.stride = fpme->vertex_size;
llvm_vert_info.verts = (struct vertex_header *)
MALLOC(fpme->vertex_size *
align(fetch_info->count, lp_native_vector_width / 32) +
DRAW_EXTRA_VERTICES_PADDING);
if (!llvm_vert_info.verts) {
assert(0);
return;
}
if (draw->collect_statistics) {
draw->statistics.ia_vertices += prim_info->count;
if (prim_info->prim == MESA_PRIM_PATCHES)
draw->statistics.ia_primitives +=
prim_info->count / draw->pt.vertices_per_patch;
else
draw->statistics.ia_primitives +=
u_decomposed_prims_for_vertices(prim_info->prim, prim_info->count);
draw->statistics.vs_invocations += fetch_info->count;
}
{
unsigned start, vertex_id_offset;
const unsigned *elts;
if (fetch_info->linear) {
start = fetch_info->start;
vertex_id_offset = draw->start_index;
elts = NULL;
} else {
start = draw->pt.user.eltMax;
vertex_id_offset = draw->pt.user.eltBias;
elts = fetch_info->elts;
}
/* Run vertex fetch shader */
clipped = fpme->current_variant->jit_func(&fpme->llvm->vs_jit_context,
&fpme->llvm->jit_resources[MESA_SHADER_VERTEX],
llvm_vert_info.verts,
draw->pt.user.vbuffer,
fetch_info->count,
start,
fpme->vertex_size,
draw->pt.vertex_buffer,
draw->instance_id,
vertex_id_offset,
draw->start_instance,
elts,
draw->pt.user.drawid,
draw->pt.user.viewid);
/* Finished with fetch and vs */
fetch_info = NULL;
vert_info = &llvm_vert_info;
}
/* Keep track of the patch lengths if we have a geometry shader, this way we can increment
* gl_PrimitiveID once per patch, instead of per tessellation output primitive.
* The Vulkan and OpenGL specs say:
* In a geometry shader, it (gl_PrimitiveID) will contain the number of primitives presented
* as input to the shader since the current set of rendering primitives was started.
* This sounds like gl_PrimitiveID will be the index of each output primitive from the
* tessellation shader, so multiple per patch. But drivers implement the more specific language
* from ARB_tessellation_shader:
* In geometry language the input variable gl_PrimitiveIDIn behaves identically to the
* tessellation control and evaluation shader input variable gl_PrimitiveID.
* Which implies on primitive index per patch. DirectX is also more specific:
* The geometry-shader stage can consume the SV_PrimitiveID system-generated value that is
* auto-generated by the IA. This allows per-primitive data to be fetched or computed if desired.
* The input-assembler (IA) stage happens before the tessellation, so we would expect one index
* per patch.
*/
uint32_t *patch_lengths = NULL;
if (opt & PT_SHADE) {
struct draw_vertex_shader *vshader = draw->vs.vertex_shader;
if (tcs_shader) {
draw_tess_ctrl_shader_run(tcs_shader,
vert_info,
prim_info,
&vshader->info,
&tcs_vert_info,
&tcs_prim_info);
FREE(vert_info->verts);
vert_info = &tcs_vert_info;
prim_info = &tcs_prim_info;
} else if (tes_shader) {
unsigned num_prims = prim_info->count / draw->pt.vertices_per_patch;
tcs_prim_info = *prim_info;
tcs_prim_info.primitive_count = num_prims;
prim_info = &tcs_prim_info;
}
if (tes_shader) {
draw_tess_eval_shader_run(tes_shader,
tcs_shader ? tcs_shader->vertices_out : draw->pt.vertices_per_patch,
vert_info,
prim_info,
tcs_shader ? &tcs_shader->info : &vshader->info,
&tes_vert_info,
&tes_prim_info,
gshader ? &patch_lengths : NULL,
&tes_elts_out);
FREE(vert_info->verts);
vert_info = &tes_vert_info;
prim_info = &tes_prim_info;
free_prim_info = true;
/*
* pt emit can only handle ushort number of vertices (see
* render->allocate_vertices).
* vsplit guarantees there's never more than 4096, however GS can
* easily blow this up (by a factor of 256 (or even 1024) max).
*/
if (vert_info->count > 65535) {
opt |= PT_PIPELINE;
}
}
}
struct draw_vertex_info gs_vert_info[TGSI_MAX_VERTEX_STREAMS];
memset(&gs_vert_info, 0, sizeof(gs_vert_info));
if ((opt & PT_SHADE) && gshader) {
struct draw_vertex_shader *vshader = draw->vs.vertex_shader;
draw_geometry_shader_run(gshader,
draw->pt.user.constants[MESA_SHADER_GEOMETRY],
vert_info,
prim_info,
tes_shader ? &tes_shader->info : &vshader->info,
tes_shader ? &patch_lengths : NULL,
gs_vert_info,
gs_prim_info);
FREE(vert_info->verts);
if (free_prim_info) {
FREE(prim_info->primitive_lengths);
FREE(tes_elts_out);
}
vert_info = &gs_vert_info[0];
prim_info = &gs_prim_info[0];
free_prim_info = false;
/*
* pt emit can only handle ushort number of vertices (see
* render->allocate_vertices).
* vsplit guarantees there's never more than 4096, however GS can
* easily blow this up (by a factor of 256 (or even 1024) max).
*/
if (vert_info->count > 65535) {
opt |= PT_PIPELINE;
}
} else {
if (!tes_shader &&
draw_prim_assembler_is_required(draw, prim_info, vert_info)) {
draw_prim_assembler_run(draw, prim_info, vert_info,
&ia_prim_info, &ia_vert_info);
if (ia_vert_info.count) {
FREE(vert_info->verts);
if (free_prim_info) {
FREE(prim_info->primitive_lengths);
FREE(tes_elts_out);
tes_elts_out = NULL;
}
vert_info = &ia_vert_info;
prim_info = &ia_prim_info;
free_prim_info = true;
}
}
}
/* stream output needs to be done before clipping */
draw_pt_so_emit(fpme->so_emit,
gshader ? gshader->num_vertex_streams : 1,
vert_info, prim_info);
/* rasterization stream selection */
if ((opt & PT_SHADE) && gshader) {
unsigned rs = draw->rasterizer->rasterization_stream;
if (rs < gshader->num_vertex_streams) {
vert_info = &gs_vert_info[rs];
prim_info = &gs_prim_info[rs];
}
}
if (prim_info->count == 0) {
// debug_printf("GS/IA didn't emit any vertices!\n");
} else {
draw_stats_clipper_primitives(draw, prim_info);
/*
* if there's no position, need to stop now, or the latter stages
* will try to access non-existent position output.
*/
if (draw_current_shader_position_output(draw) != -1) {
if ((opt & PT_SHADE) &&
(gshader || tes_shader ||
draw->vs.vertex_shader->info.writes_viewport_index)) {
clipped = draw_pt_post_vs_run(fpme->post_vs, vert_info, prim_info);
}
/* "clipped" also includes non-one edgeflag */
if (clipped) {
opt |= PT_PIPELINE;
}
/* Do we need to run the pipeline? Now will come here if clipped */
if (opt & PT_PIPELINE) {
pipeline(fpme, vert_info, prim_info);
} else {
emit(fpme->emit, vert_info, prim_info);
}
}
}
if ((opt & PT_SHADE) && gshader) {
for (unsigned i = 0; i < gshader->num_vertex_streams; i++)
FREE(gs_vert_info[i].verts);
} else {
FREE(vert_info->verts);
}
FREE(patch_lengths);
if (free_prim_info) {
FREE(tes_elts_out);
FREE(prim_info->primitive_lengths);
}
}
static inline enum mesa_prim
prim_type(enum mesa_prim prim, unsigned flags)
{
if (flags & DRAW_LINE_LOOP_AS_STRIP)
return MESA_PRIM_LINE_STRIP;
else
return prim;
}
static void
llvm_middle_end_run(struct draw_pt_middle_end *middle,
unsigned start,
const unsigned *fetch_elts,
unsigned fetch_count,
const uint16_t *draw_elts,
unsigned draw_count,
unsigned prim_flags)
{
struct llvm_middle_end *fpme = llvm_middle_end(middle);
struct draw_fetch_info fetch_info;
struct draw_prim_info prim_info;
fetch_info.linear = false;
fetch_info.start = start;
fetch_info.elts = fetch_elts;
fetch_info.count = fetch_count;
prim_info.linear = false;
prim_info.start = start - fpme->draw->start_index;
prim_info.count = draw_count;
prim_info.elts = draw_elts;
prim_info.prim = prim_type(fpme->input_prim, prim_flags);
prim_info.flags = prim_flags;
prim_info.primitive_count = 1;
prim_info.primitive_lengths = &draw_count;
llvm_pipeline_generic(middle, &fetch_info, &prim_info);
}
static void
llvm_middle_end_linear_run(struct draw_pt_middle_end *middle,
unsigned start,
unsigned count,
unsigned prim_flags)
{
struct llvm_middle_end *fpme = llvm_middle_end(middle);
struct draw_fetch_info fetch_info;
struct draw_prim_info prim_info;
fetch_info.linear = true;
fetch_info.start = start;
fetch_info.count = count;
fetch_info.elts = NULL;
prim_info.linear = true;
prim_info.start = start - fpme->draw->start_index;
prim_info.count = count;
prim_info.elts = NULL;
prim_info.prim = prim_type(fpme->input_prim, prim_flags);
prim_info.flags = prim_flags;
prim_info.primitive_count = 1;
prim_info.primitive_lengths = &count;
llvm_pipeline_generic(middle, &fetch_info, &prim_info);
}
static bool
llvm_middle_end_linear_run_elts(struct draw_pt_middle_end *middle,
unsigned start,
unsigned count,
const uint16_t *draw_elts,
unsigned draw_start,
unsigned draw_count)
{
struct llvm_middle_end *fpme = llvm_middle_end(middle);
struct draw_fetch_info fetch_info;
struct draw_prim_info prim_info;
fetch_info.linear = true;
fetch_info.start = start;
fetch_info.count = count;
fetch_info.elts = NULL;
prim_info.linear = false;
prim_info.start = draw_start - fpme->draw->start_index;
prim_info.count = draw_count;
prim_info.elts = draw_elts;
prim_info.prim = fpme->input_prim;
prim_info.flags = 0;
prim_info.primitive_count = 1;
prim_info.primitive_lengths = &draw_count;
llvm_pipeline_generic(middle, &fetch_info, &prim_info);
return true;
}
static void
llvm_middle_end_finish(struct draw_pt_middle_end *middle)
{
/* nothing to do */
}
static void
llvm_middle_end_destroy(struct draw_pt_middle_end *middle)
{
struct llvm_middle_end *fpme = llvm_middle_end(middle);
if (fpme->fetch)
draw_pt_fetch_destroy(fpme->fetch);
if (fpme->emit)
draw_pt_emit_destroy(fpme->emit);
if (fpme->so_emit)
draw_pt_so_emit_destroy(fpme->so_emit);
if (fpme->post_vs)
draw_pt_post_vs_destroy(fpme->post_vs);
FREE(middle);
}
struct draw_pt_middle_end *
draw_pt_fetch_pipeline_or_emit_llvm(struct draw_context *draw)
{
struct llvm_middle_end *fpme = 0;
if (!draw->llvm)
return NULL;
fpme = CALLOC_STRUCT(llvm_middle_end);
if (!fpme)
goto fail;
fpme->base.prepare = llvm_middle_end_prepare;
fpme->base.bind_parameters = llvm_middle_end_bind_parameters;
fpme->base.run = llvm_middle_end_run;
fpme->base.run_linear = llvm_middle_end_linear_run;
fpme->base.run_linear_elts = llvm_middle_end_linear_run_elts;
fpme->base.finish = llvm_middle_end_finish;
fpme->base.destroy = llvm_middle_end_destroy;
fpme->draw = draw;
fpme->fetch = draw_pt_fetch_create(draw);
if (!fpme->fetch)
goto fail;
fpme->post_vs = draw_pt_post_vs_create(draw);
if (!fpme->post_vs)
goto fail;
fpme->emit = draw_pt_emit_create(draw);
if (!fpme->emit)
goto fail;
fpme->so_emit = draw_pt_so_emit_create(draw);
if (!fpme->so_emit)
goto fail;
fpme->llvm = draw->llvm;
if (!fpme->llvm)
goto fail;
fpme->current_variant = NULL;
return &fpme->base;
fail:
if (fpme)
llvm_middle_end_destroy(&fpme->base);
return NULL;
}
@@ -0,0 +1,131 @@
/**************************************************************************
*
* Copyright 2023 Red Hat.
* 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
* 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 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.
*
**************************************************************************/
#include "draw/draw_context.h"
#include "draw/draw_private.h"
#include "draw/draw_pt.h"
#include "draw/draw_mesh.h"
/*
* Mesh shader middle end,
* This doesn't need a frontend as mesh shader frontend
* is done with compute shaders in llvmpipe.
*/
struct mesh_pipeline_middle_end {
struct draw_pt_middle_end base;
struct draw_context *draw;
struct pt_so_emit *so_emit;
struct pt_post_vs *post_vs;
};
/** cast wrapper */
static inline struct mesh_pipeline_middle_end *
mesh_pipeline_middle_end(struct draw_pt_middle_end *middle)
{
return (struct mesh_pipeline_middle_end *) middle;
}
static void
mesh_pipeline_destroy(struct draw_pt_middle_end *middle)
{
struct mesh_pipeline_middle_end *mpme = mesh_pipeline_middle_end(middle);
if (mpme->so_emit)
draw_pt_so_emit_destroy(mpme->so_emit);
if (mpme->post_vs)
draw_pt_post_vs_destroy(mpme->post_vs);
FREE(middle);
}
static void
mesh_middle_end_prepare(struct draw_pt_middle_end *middle,
enum mesa_prim prim,
unsigned opt,
unsigned *max_vertices)
{
struct mesh_pipeline_middle_end *mpme = mesh_pipeline_middle_end(middle);
struct draw_context *draw = mpme->draw;
enum mesa_prim out_prim = draw->ms.mesh_shader->output_primitive;
unsigned point_clip = draw->rasterizer->fill_front == PIPE_POLYGON_MODE_POINT ||
out_prim == MESA_PRIM_POINTS;
draw_pt_post_vs_prepare(mpme->post_vs,
draw->clip_xy,
draw->clip_z,
draw->clip_user,
point_clip ? draw->guard_band_points_lines_xy :
draw->guard_band_xy,
draw->bypass_viewport,
draw->rasterizer->clip_halfz,
false);
draw_pt_so_emit_prepare(mpme->so_emit, false);
draw_do_flush(draw, DRAW_FLUSH_BACKEND);
}
void
draw_mesh_middle_end_run(struct draw_pt_middle_end *middle,
struct draw_vertex_info *vert_info,
struct draw_prim_info *prim_info)
{
struct mesh_pipeline_middle_end *mpme = mesh_pipeline_middle_end(middle);
draw_pt_post_vs_run(mpme->post_vs, vert_info, prim_info);
/* just for primgen query */
draw_pt_so_emit(mpme->so_emit, 1, vert_info, prim_info);
draw_pipeline_run_linear(mpme->draw, vert_info, prim_info);
}
struct draw_pt_middle_end *
draw_pt_mesh_pipeline_or_emit(struct draw_context *draw)
{
struct mesh_pipeline_middle_end *mpme =
CALLOC_STRUCT(mesh_pipeline_middle_end);
if (!mpme)
goto fail;
mpme->base.prepare = mesh_middle_end_prepare;
mpme->base.destroy = mesh_pipeline_destroy;
mpme->draw = draw;
mpme->post_vs = draw_pt_post_vs_create(draw);
if (!mpme->post_vs)
goto fail;
mpme->so_emit = draw_pt_so_emit_create(draw);
if (!mpme->so_emit)
goto fail;
return &mpme->base;
fail:
if (mpme)
mesh_pipeline_destroy(&mpme->base);
return NULL;
}
@@ -0,0 +1,234 @@
/**************************************************************************
*
* Copyright 2008 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 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 ITS 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 "util/u_memory.h"
#include "util/u_math.h"
#include "util/u_prim.h"
#include "pipe/p_context.h"
#include "draw/draw_context.h"
#include "draw/draw_private.h"
#include "draw/draw_pt.h"
#include "draw/draw_vs.h"
#define DO_CLIP_XY 0x1
#define DO_CLIP_FULL_Z 0x2
#define DO_CLIP_HALF_Z 0x4
#define DO_CLIP_USER 0x8
#define DO_VIEWPORT 0x10
#define DO_EDGEFLAG 0x20
#define DO_CLIP_XY_GUARD_BAND 0x40
struct pt_post_vs {
struct draw_context *draw;
unsigned flags;
bool (*run)(struct pt_post_vs *pvs,
struct draw_vertex_info *info,
const struct draw_prim_info *prim_info);
};
static inline void
initialize_vertex_header(struct vertex_header *header)
{
header->clipmask = 0;
header->edgeflag = 1;
header->pad = 0;
header->vertex_id = UNDEFINED_VERTEX_ID;
}
static inline float
dot4(const float *a, const float *b)
{
return (a[0] * b[0] +
a[1] * b[1] +
a[2] * b[2] +
a[3] * b[3]);
}
#define FLAGS (0)
#define TAG(x) x##_none
#include "draw_cliptest_tmp.h"
#define FLAGS (DO_CLIP_XY | DO_CLIP_FULL_Z | DO_VIEWPORT)
#define TAG(x) x##_xy_fullz_viewport
#include "draw_cliptest_tmp.h"
#define FLAGS (DO_CLIP_XY | DO_CLIP_HALF_Z | DO_VIEWPORT)
#define TAG(x) x##_xy_halfz_viewport
#include "draw_cliptest_tmp.h"
#define FLAGS (DO_CLIP_XY_GUARD_BAND | DO_CLIP_HALF_Z | DO_VIEWPORT)
#define TAG(x) x##_xy_gb_halfz_viewport
#include "draw_cliptest_tmp.h"
#define FLAGS (DO_CLIP_XY_GUARD_BAND | DO_CLIP_FULL_Z | DO_VIEWPORT)
#define TAG(x) x##_xy_gb_fullz_viewport
#include "draw_cliptest_tmp.h"
#define FLAGS (DO_CLIP_FULL_Z | DO_VIEWPORT)
#define TAG(x) x##_fullz_viewport
#include "draw_cliptest_tmp.h"
#define FLAGS (DO_CLIP_HALF_Z | DO_VIEWPORT)
#define TAG(x) x##_halfz_viewport
#include "draw_cliptest_tmp.h"
#define FLAGS (DO_CLIP_XY | DO_CLIP_FULL_Z | DO_CLIP_USER | DO_VIEWPORT)
#define TAG(x) x##_xy_fullz_user_viewport
#include "draw_cliptest_tmp.h"
#define FLAGS (DO_CLIP_XY | DO_CLIP_FULL_Z | DO_CLIP_USER | DO_VIEWPORT | DO_EDGEFLAG)
#define TAG(x) x##_xy_fullz_user_viewport_edgeflag
#include "draw_cliptest_tmp.h"
/* Don't want to create 64 versions of this function, so catch the
* less common ones here. This is looking like something which should
* be code-generated, perhaps appended to the end of the vertex
* shader.
*/
#define FLAGS (pvs->flags)
#define TAG(x) x##_generic
#include "draw_cliptest_tmp.h"
bool
draw_pt_post_vs_run(struct pt_post_vs *pvs,
struct draw_vertex_info *info,
const struct draw_prim_info *prim_info)
{
return pvs->run(pvs, info, prim_info);
}
void
draw_pt_post_vs_prepare(struct pt_post_vs *pvs,
bool clip_xy,
bool clip_z,
bool clip_user,
bool guard_band,
bool bypass_viewport,
bool clip_halfz,
bool need_edgeflags)
{
pvs->flags = 0;
if (clip_xy && !guard_band) {
pvs->flags |= DO_CLIP_XY;
ASSIGN_4V(pvs->draw->plane[0], -1, 0, 0, 1);
ASSIGN_4V(pvs->draw->plane[1], 1, 0, 0, 1);
ASSIGN_4V(pvs->draw->plane[2], 0, -1, 0, 1);
ASSIGN_4V(pvs->draw->plane[3], 0, 1, 0, 1);
} else if (clip_xy && guard_band) {
pvs->flags |= DO_CLIP_XY_GUARD_BAND;
ASSIGN_4V(pvs->draw->plane[0], -0.5, 0, 0, 1);
ASSIGN_4V(pvs->draw->plane[1], 0.5, 0, 0, 1);
ASSIGN_4V(pvs->draw->plane[2], 0, -0.5, 0, 1);
ASSIGN_4V(pvs->draw->plane[3], 0, 0.5, 0, 1);
}
if (clip_z) {
if (clip_halfz) {
pvs->flags |= DO_CLIP_HALF_Z;
ASSIGN_4V(pvs->draw->plane[4], 0, 0, 1, 0);
} else {
pvs->flags |= DO_CLIP_FULL_Z;
ASSIGN_4V(pvs->draw->plane[4], 0, 0, 1, 1);
}
}
if (clip_user)
pvs->flags |= DO_CLIP_USER;
if (!bypass_viewport)
pvs->flags |= DO_VIEWPORT;
if (need_edgeflags)
pvs->flags |= DO_EDGEFLAG;
/* Now select the relevant function:
*/
switch (pvs->flags) {
case 0:
pvs->run = do_cliptest_none;
break;
case DO_CLIP_XY | DO_CLIP_FULL_Z | DO_VIEWPORT:
pvs->run = do_cliptest_xy_fullz_viewport;
break;
case DO_CLIP_XY | DO_CLIP_HALF_Z | DO_VIEWPORT:
pvs->run = do_cliptest_xy_halfz_viewport;
break;
case DO_CLIP_XY_GUARD_BAND | DO_CLIP_HALF_Z | DO_VIEWPORT:
pvs->run = do_cliptest_xy_gb_halfz_viewport;
break;
case DO_CLIP_XY_GUARD_BAND | DO_CLIP_FULL_Z | DO_VIEWPORT:
pvs->run = do_cliptest_xy_gb_fullz_viewport;
break;
case DO_CLIP_FULL_Z | DO_VIEWPORT:
pvs->run = do_cliptest_fullz_viewport;
break;
case DO_CLIP_HALF_Z | DO_VIEWPORT:
pvs->run = do_cliptest_halfz_viewport;
break;
case DO_CLIP_XY | DO_CLIP_FULL_Z | DO_CLIP_USER | DO_VIEWPORT:
pvs->run = do_cliptest_xy_fullz_user_viewport;
break;
case (DO_CLIP_XY | DO_CLIP_FULL_Z | DO_CLIP_USER |
DO_VIEWPORT | DO_EDGEFLAG):
pvs->run = do_cliptest_xy_fullz_user_viewport_edgeflag;
break;
default:
pvs->run = do_cliptest_generic;
break;
}
}
struct pt_post_vs *
draw_pt_post_vs_create(struct draw_context *draw)
{
struct pt_post_vs *pvs = CALLOC_STRUCT(pt_post_vs);
if (!pvs)
return NULL;
pvs->draw = draw;
return pvs;
}
void
draw_pt_post_vs_destroy(struct pt_post_vs *pvs)
{
FREE(pvs);
}
@@ -0,0 +1,347 @@
/**************************************************************************
*
* Copyright 2010 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 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 ITS 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 "draw/draw_private.h"
#include "draw/draw_vs.h"
#include "draw/draw_gs.h"
#include "draw/draw_tess.h"
#include "draw/draw_context.h"
#include "draw/draw_vbuf.h"
#include "draw/draw_vertex.h"
#include "draw/draw_pt.h"
#include "pipe/p_state.h"
#include "util/u_math.h"
#include "util/u_prim.h"
#include "util/u_memory.h"
struct pt_so_emit {
struct draw_context *draw;
unsigned input_vertex_stride;
const float (*inputs)[4];
const float *pre_clip_pos;
bool has_so;
bool use_pre_clip_pos;
int pos_idx;
unsigned emitted_primitives;
unsigned generated_primitives;
unsigned stream;
};
static const struct pipe_stream_output_info *
draw_so_info(const struct draw_context *draw)
{
const struct pipe_stream_output_info *state = NULL;
if (draw->ms.mesh_shader)
return state;
if (draw->gs.geometry_shader) {
state = &draw->gs.geometry_shader->state.stream_output;
} else if (draw->tes.tess_eval_shader) {
state = &draw->tes.tess_eval_shader->state.stream_output;
} else {
state = &draw->vs.vertex_shader->state.stream_output;
}
return state;
}
static inline bool
draw_has_so(const struct draw_context *draw)
{
const struct pipe_stream_output_info *state = draw_so_info(draw);
if (state && state->num_outputs > 0)
return true;
return false;
}
void
draw_pt_so_emit_prepare(struct pt_so_emit *emit, bool use_pre_clip_pos)
{
struct draw_context *draw = emit->draw;
emit->use_pre_clip_pos = use_pre_clip_pos;
emit->has_so = draw_has_so(draw);
if (use_pre_clip_pos)
emit->pos_idx = draw_current_shader_position_output(draw);
/* if we have a state with outputs make sure we have
* buffers to output to */
if (emit->has_so) {
bool has_valid_buffer = false;
for (unsigned i = 0; i < draw->so.num_targets; ++i) {
if (draw->so.targets[i]) {
has_valid_buffer = true;
break;
}
}
emit->has_so = has_valid_buffer;
}
if (!emit->has_so)
return;
/* XXX: need to flush to get prim_vbuf.c to release its allocation??
*/
draw_do_flush(draw, DRAW_FLUSH_BACKEND);
}
static void
so_emit_prim(struct pt_so_emit *so,
unsigned *indices,
unsigned num_vertices)
{
unsigned input_vertex_stride = so->input_vertex_stride;
struct draw_context *draw = so->draw;
const float (*input_ptr)[4];
const float *pcp_ptr = NULL;
const struct pipe_stream_output_info *state = draw_so_info(draw);
int buffer_total_bytes[PIPE_MAX_SO_BUFFERS];
bool buffer_written[PIPE_MAX_SO_BUFFERS] = {0};
input_ptr = so->inputs;
if (so->use_pre_clip_pos)
pcp_ptr = so->pre_clip_pos;
++so->generated_primitives;
for (unsigned i = 0; i < draw->so.num_targets; i++) {
struct draw_so_target *target = draw->so.targets[i];
if (target) {
buffer_total_bytes[i] = target->internal_offset;
} else {
buffer_total_bytes[i] = 0;
}
}
/* check have we space to emit prim first - if not don't do anything */
for (unsigned slot = 0; slot < state->num_outputs; ++slot) {
int ob = state->output[slot].output_buffer;
if (state->output[slot].stream != so->stream)
continue;
/* If a buffer is missing then that's equivalent to an overflow */
if (!draw->so.targets[ob]) {
return;
}
buffer_written[ob] = true;
}
for (unsigned ob = 0; ob < draw->so.num_targets; ++ob) {
if (buffer_written[ob]) {
unsigned size_req = num_vertices * state->stride[ob] * sizeof(float);
if (buffer_total_bytes[ob] + size_req > draw->so.targets[ob]->target.buffer_size) {
return;
}
}
}
for (unsigned i = 0; i < num_vertices; ++i) {
const float (*input)[4];
const float *pre_clip_pos = NULL;
input = (const float (*)[4])(
(const char *)input_ptr + (indices[i] * input_vertex_stride));
if (pcp_ptr)
pre_clip_pos = (const float *)(
(const char *)pcp_ptr + (indices[i] * input_vertex_stride));
for (unsigned slot = 0; slot < state->num_outputs; ++slot) {
unsigned idx = state->output[slot].register_index;
unsigned start_comp = state->output[slot].start_component;
unsigned num_comps = state->output[slot].num_components;
unsigned stream = state->output[slot].stream;
if (stream != so->stream)
continue;
unsigned ob = state->output[slot].output_buffer;
float *buffer = (float *)((char *)draw->so.targets[ob]->mapping +
draw->so.targets[ob]->target.buffer_offset +
draw->so.targets[ob]->internal_offset) +
state->output[slot].dst_offset;
if (idx == so->pos_idx && pcp_ptr && so->stream == 0) {
memcpy(buffer, &pre_clip_pos[start_comp],
num_comps * sizeof(float));
} else {
memcpy(buffer, &input[idx][start_comp],
num_comps * sizeof(float));
}
#if 0
{
debug_printf("VERT[%d], stream = %d, offset = %d, slot[%d] sc = %d, num_c = %d, idx = %d = [",
i, stream,
draw->so.targets[ob]->internal_offset + (4 * state->output[slot].dst_offset),
slot, start_comp, num_comps, idx);
for (unsigned j = 0; j < num_comps; ++j) {
unsigned *ubuffer = (unsigned*)buffer;
debug_printf("%d (0x%x), ", ubuffer[j], ubuffer[j]);
}
debug_printf("]\n");
}
#endif
}
for (unsigned ob = 0; ob < draw->so.num_targets; ++ob) {
struct draw_so_target *target = draw->so.targets[ob];
if (target && buffer_written[ob]) {
target->internal_offset += state->stride[ob] * sizeof(float);
}
}
}
++so->emitted_primitives;
}
static void
so_point(struct pt_so_emit *so, int idx)
{
unsigned indices[1];
indices[0] = idx;
so_emit_prim(so, indices, 1);
}
static void
so_line(struct pt_so_emit *so, int i0, int i1)
{
unsigned indices[2];
indices[0] = i0;
indices[1] = i1;
so_emit_prim(so, indices, 2);
}
static void
so_tri(struct pt_so_emit *so, int i0, int i1, int i2)
{
unsigned indices[3];
indices[0] = i0;
indices[1] = i1;
indices[2] = i2;
so_emit_prim(so, indices, 3);
}
#define FUNC so_run_linear
#define GET_ELT(idx) (start + (idx))
#include "draw_so_emit_tmp.h"
#define FUNC so_run_elts
#define LOCAL_VARS const uint16_t *elts = input_prims->elts;
#define GET_ELT(idx) (elts[start + (idx)])
#include "draw_so_emit_tmp.h"
void
draw_pt_so_emit(struct pt_so_emit *emit,
int num_vertex_streams,
const struct draw_vertex_info *input_verts,
const struct draw_prim_info *input_prims)
{
struct draw_context *draw = emit->draw;
struct vbuf_render *render = draw->render;
if (!emit->has_so && num_vertex_streams == 1) {
if (draw->collect_primgen) {
unsigned total = 0;
for (unsigned i = 0; i < input_prims->primitive_count; i++) {
total +=
u_decomposed_prims_for_vertices(input_prims->prim,
input_prims->primitive_lengths[i]);
}
render->set_stream_output_info(render, 0, 0, total);
}
return;
}
if (!emit->has_so && !draw->collect_primgen)
return;
/* XXX: need to flush to get prim_vbuf.c to release its allocation??*/
draw_do_flush(draw, DRAW_FLUSH_BACKEND);
for (unsigned stream = 0; stream < num_vertex_streams; stream++) {
emit->emitted_primitives = 0;
emit->generated_primitives = 0;
if (emit->use_pre_clip_pos)
emit->pre_clip_pos = input_verts[stream].verts->clip_pos;
emit->input_vertex_stride = input_verts[stream].stride;
emit->inputs = (const float (*)[4])input_verts[stream].verts->data;
emit->stream = stream;
unsigned start, i;
for (start = i = 0; i < input_prims[stream].primitive_count;
start += input_prims[stream].primitive_lengths[i], i++) {
unsigned count = input_prims[stream].primitive_lengths[i];
if (input_prims->linear) {
so_run_linear(emit, &input_prims[stream], &input_verts[stream],
start, count);
} else {
so_run_elts(emit, &input_prims[stream], &input_verts[stream],
start, count);
}
}
render->set_stream_output_info(render,
stream,
emit->has_so ? emit->emitted_primitives : 0,
emit->generated_primitives);
}
}
struct pt_so_emit *
draw_pt_so_emit_create(struct draw_context *draw)
{
struct pt_so_emit *emit = CALLOC_STRUCT(pt_so_emit);
if (!emit)
return NULL;
emit->draw = draw;
return emit;
}
void
draw_pt_so_emit_destroy(struct pt_so_emit *emit)
{
FREE(emit);
}
+105
View File
@@ -0,0 +1,105 @@
/**************************************************************************
*
* Copyright 2007 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 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 ITS 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.
*
**************************************************************************/
/*
* Authors:
* Keith Whitwell <[email protected]>
*/
#include "draw/draw_context.h"
#include "draw/draw_private.h"
#include "draw/draw_pt.h"
#include "util/u_debug.h"
void
draw_pt_split_prim(enum mesa_prim prim, unsigned *first, unsigned *incr)
{
switch (prim) {
case MESA_PRIM_POINTS:
*first = 1;
*incr = 1;
break;
case MESA_PRIM_LINES:
*first = 2;
*incr = 2;
break;
case MESA_PRIM_LINE_STRIP:
case MESA_PRIM_LINE_LOOP:
*first = 2;
*incr = 1;
break;
case MESA_PRIM_LINES_ADJACENCY:
*first = 4;
*incr = 4;
break;
case MESA_PRIM_LINE_STRIP_ADJACENCY:
*first = 4;
*incr = 1;
break;
case MESA_PRIM_TRIANGLES:
*first = 3;
*incr = 3;
break;
case MESA_PRIM_TRIANGLES_ADJACENCY:
*first = 6;
*incr = 6;
break;
case MESA_PRIM_TRIANGLE_STRIP:
case MESA_PRIM_TRIANGLE_FAN:
case MESA_PRIM_POLYGON:
*first = 3;
*incr = 1;
break;
case MESA_PRIM_TRIANGLE_STRIP_ADJACENCY:
*first = 6;
*incr = 2;
break;
case MESA_PRIM_QUADS:
*first = 4;
*incr = 4;
break;
case MESA_PRIM_QUAD_STRIP:
*first = 4;
*incr = 2;
break;
default:
assert(0);
*first = 0;
*incr = 1; /* set to one so that count % incr works */
break;
}
}
unsigned
draw_pt_trim_count(unsigned count, unsigned first, unsigned incr)
{
if (count < first)
return 0;
return count - (count - first) % incr;
}
+277
View File
@@ -0,0 +1,277 @@
/*
* Mesa 3-D graphics library
*
* Copyright 2007-2008 VMware, Inc.
* Copyright (C) 2010 LunarG Inc.
*
* 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 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.
*/
#include <stdbool.h>
#include "util/macros.h"
#include "util/u_math.h"
#include "util/u_memory.h"
#include "draw/draw_context.h"
#include "draw/draw_private.h"
#include "draw/draw_pt.h"
#define SEGMENT_SIZE 1024
#define MAP_SIZE 256
struct vsplit_frontend {
struct draw_pt_front_end base;
struct draw_context *draw;
enum mesa_prim prim;
struct draw_pt_middle_end *middle;
unsigned max_vertices;
uint16_t segment_size;
/* buffers for splitting */
unsigned fetch_elts[SEGMENT_SIZE];
uint16_t draw_elts[SEGMENT_SIZE];
uint16_t identity_draw_elts[SEGMENT_SIZE];
struct {
/* map a fetch element to a draw element */
unsigned fetches[MAP_SIZE];
uint16_t draws[MAP_SIZE];
bool has_max_fetch;
uint16_t num_fetch_elts;
uint16_t num_draw_elts;
} cache;
};
static void
vsplit_clear_cache(struct vsplit_frontend *vsplit)
{
memset(vsplit->cache.fetches, 0xff, sizeof(vsplit->cache.fetches));
vsplit->cache.has_max_fetch = false;
vsplit->cache.num_fetch_elts = 0;
vsplit->cache.num_draw_elts = 0;
}
static void
vsplit_flush_cache(struct vsplit_frontend *vsplit, unsigned start, unsigned flags)
{
vsplit->middle->run(vsplit->middle, start,
vsplit->fetch_elts, vsplit->cache.num_fetch_elts,
vsplit->draw_elts, vsplit->cache.num_draw_elts, flags);
}
/**
* Add a fetch element and add it to the draw elements.
*/
static inline void
vsplit_add_cache(struct vsplit_frontend *vsplit, unsigned fetch)
{
unsigned hash;
hash = fetch % MAP_SIZE;
/* If the value isn't in the cache or it's an overflow due to the
* element bias */
if (vsplit->cache.fetches[hash] != fetch) {
/* update cache */
vsplit->cache.fetches[hash] = fetch;
vsplit->cache.draws[hash] = vsplit->cache.num_fetch_elts;
/* add fetch */
assert(vsplit->cache.num_fetch_elts < vsplit->segment_size);
vsplit->fetch_elts[vsplit->cache.num_fetch_elts++] = fetch;
}
vsplit->draw_elts[vsplit->cache.num_draw_elts++] = vsplit->cache.draws[hash];
}
/**
* Returns the base index to the elements array.
* The value is checked for integer overflow (not sure it can happen?).
*/
static inline unsigned
vsplit_get_base_idx(unsigned start, unsigned fetch)
{
return util_clamped_uadd(start, fetch);
}
static inline void
vsplit_add_cache_uint8(struct vsplit_frontend *vsplit, const uint8_t *elts,
unsigned start, unsigned fetch, int elt_bias)
{
struct draw_context *draw = vsplit->draw;
unsigned elt_idx;
elt_idx = vsplit_get_base_idx(start, fetch);
elt_idx = (unsigned)((int)(DRAW_GET_IDX(elts, elt_idx)) + elt_bias);
/* unlike the uint32_t case this can only happen with elt_bias */
if (elt_bias && elt_idx == DRAW_MAX_FETCH_IDX && !vsplit->cache.has_max_fetch) {
unsigned hash = elt_idx % MAP_SIZE;
vsplit->cache.fetches[hash] = 0;
vsplit->cache.has_max_fetch = true;
}
vsplit_add_cache(vsplit, elt_idx);
}
static inline void
vsplit_add_cache_uint16(struct vsplit_frontend *vsplit, const uint16_t *elts,
unsigned start, unsigned fetch, int elt_bias)
{
struct draw_context *draw = vsplit->draw;
unsigned elt_idx;
elt_idx = vsplit_get_base_idx(start, fetch);
elt_idx = (unsigned)((int)(DRAW_GET_IDX(elts, elt_idx)) + elt_bias);
/* unlike the uint32_t case this can only happen with elt_bias */
if (elt_bias && elt_idx == DRAW_MAX_FETCH_IDX && !vsplit->cache.has_max_fetch) {
unsigned hash = elt_idx % MAP_SIZE;
vsplit->cache.fetches[hash] = 0;
vsplit->cache.has_max_fetch = true;
}
vsplit_add_cache(vsplit, elt_idx);
}
/**
* Add a fetch element and add it to the draw elements. The fetch element is
* in full range (uint32_t).
*/
static inline void
vsplit_add_cache_uint32(struct vsplit_frontend *vsplit, const uint32_t *elts,
unsigned start, unsigned fetch, int elt_bias)
{
struct draw_context *draw = vsplit->draw;
unsigned elt_idx;
/*
* The final element index is just element index plus element bias.
*/
elt_idx = vsplit_get_base_idx(start, fetch);
elt_idx = (unsigned)((int)(DRAW_GET_IDX(elts, elt_idx)) + elt_bias);
/* Take care for DRAW_MAX_FETCH_IDX (since cache is initialized to -1). */
if (elt_idx == DRAW_MAX_FETCH_IDX && !vsplit->cache.has_max_fetch) {
unsigned hash = elt_idx % MAP_SIZE;
/* force update - any value will do except DRAW_MAX_FETCH_IDX */
vsplit->cache.fetches[hash] = 0;
vsplit->cache.has_max_fetch = true;
}
vsplit_add_cache(vsplit, elt_idx);
}
#define FUNC vsplit_run_linear
#include "draw_pt_vsplit_tmp.h"
#define FUNC vsplit_run_uint8
#define ELT_TYPE uint8_t
#define ADD_CACHE(vsplit, ib, start, fetch, bias) vsplit_add_cache_uint8(vsplit,ib,start,fetch,bias)
#include "draw_pt_vsplit_tmp.h"
#define FUNC vsplit_run_uint16
#define ELT_TYPE uint16_t
#define ADD_CACHE(vsplit, ib, start, fetch, bias) vsplit_add_cache_uint16(vsplit,ib,start,fetch, bias)
#include "draw_pt_vsplit_tmp.h"
#define FUNC vsplit_run_uint32
#define ELT_TYPE uint32_t
#define ADD_CACHE(vsplit, ib, start, fetch, bias) vsplit_add_cache_uint32(vsplit, ib, start, fetch, bias)
#include "draw_pt_vsplit_tmp.h"
static void
vsplit_prepare(struct draw_pt_front_end *frontend,
enum mesa_prim in_prim,
struct draw_pt_middle_end *middle,
unsigned opt)
{
struct vsplit_frontend *vsplit = (struct vsplit_frontend *) frontend;
switch (vsplit->draw->pt.user.eltSize) {
case 0:
vsplit->base.run = vsplit_run_linear;
break;
case 1:
vsplit->base.run = vsplit_run_uint8;
break;
case 2:
vsplit->base.run = vsplit_run_uint16;
break;
case 4:
vsplit->base.run = vsplit_run_uint32;
break;
default:
assert(0);
break;
}
/* split only */
vsplit->prim = in_prim;
vsplit->middle = middle;
middle->prepare(middle, vsplit->prim, opt, &vsplit->max_vertices);
vsplit->segment_size = MIN2(SEGMENT_SIZE, vsplit->max_vertices);
}
static void
vsplit_flush(struct draw_pt_front_end *frontend, unsigned flags)
{
struct vsplit_frontend *vsplit = (struct vsplit_frontend *) frontend;
if (flags & DRAW_FLUSH_STATE_CHANGE) {
vsplit->middle->finish(vsplit->middle);
vsplit->middle = NULL;
}
}
static void
vsplit_destroy(struct draw_pt_front_end *frontend)
{
FREE(frontend);
}
struct draw_pt_front_end *
draw_pt_vsplit(struct draw_context *draw)
{
struct vsplit_frontend *vsplit = CALLOC_STRUCT(vsplit_frontend);
if (!vsplit)
return NULL;
vsplit->base.prepare = vsplit_prepare;
vsplit->base.run = NULL;
vsplit->base.flush = vsplit_flush;
vsplit->base.destroy = vsplit_destroy;
vsplit->draw = draw;
for (unsigned i = 0; i < SEGMENT_SIZE; i++)
vsplit->identity_draw_elts[i] = i;
return &vsplit->base;
}
@@ -0,0 +1,305 @@
/*
* Mesa 3-D graphics library
*
* Copyright 2007-2008 VMware, Inc.
* Copyright (C) 2010 LunarG Inc.
*
* 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 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.
*/
#ifdef ELT_TYPE
/**
* Fetch all elements in [min_index, max_index] with bias, and use the
* (rebased) index buffer as the draw elements.
*/
static bool
CONCAT2(vsplit_primitive_, ELT_TYPE)(struct vsplit_frontend *vsplit,
unsigned istart, unsigned icount)
{
struct draw_context *draw = vsplit->draw;
const ELT_TYPE *ib = (const ELT_TYPE *) draw->pt.user.elts;
const unsigned min_index = draw->pt.user.min_index;
const unsigned max_index = draw->pt.user.max_index;
const int elt_bias = draw->pt.user.eltBias;
unsigned fetch_start, fetch_count;
const uint16_t *draw_elts = NULL;
const unsigned start = istart;
const unsigned end = istart + icount;
/* If the index buffer overflows we'll need to run
* through the normal paths */
if (end >= draw->pt.user.eltMax ||
end < istart)
return false;
/* use the ib directly */
if (min_index == 0 && sizeof(ib[0]) == sizeof(draw_elts[0])) {
if (icount > vsplit->max_vertices)
return false;
for (unsigned i = 0; i < icount; i++) {
ELT_TYPE idx = DRAW_GET_IDX(ib, start + i);
if (idx < min_index || idx > max_index) {
debug_printf("warning: index out of range\n");
}
}
draw_elts = (const uint16_t *) (ib + istart);
} else {
/* have to go through vsplit->draw_elts */
if (icount > vsplit->segment_size)
return false;
}
/* this is faster only when we fetch less elements than the normal path */
if (max_index - min_index > icount - 1)
return false;
if (elt_bias < 0 && (int) min_index < -elt_bias)
return false;
/* why this check? */
for (unsigned i = 0; i < draw->pt.nr_vertex_elements; i++) {
if (draw->pt.vertex_element[i].instance_divisor)
return false;
}
fetch_start = min_index + elt_bias;
fetch_count = max_index - min_index + 1;
/* Check for overflow in the fetch_start */
if (fetch_start < min_index || fetch_start < elt_bias)
return false;
if (!draw_elts) {
if (min_index == 0) {
for (unsigned i = 0; i < icount; i++) {
ELT_TYPE idx = DRAW_GET_IDX(ib, i + start);
if (idx < min_index || idx > max_index) {
debug_printf("warning: index out of range\n");
}
vsplit->draw_elts[i] = (uint16_t) idx;
}
} else {
for (unsigned i = 0; i < icount; i++) {
ELT_TYPE idx = DRAW_GET_IDX(ib, i + start);
if (idx < min_index || idx > max_index) {
debug_printf("warning: index out of range\n");
}
vsplit->draw_elts[i] = (uint16_t) (idx - min_index);
}
}
draw_elts = vsplit->draw_elts;
}
return vsplit->middle->run_linear_elts(vsplit->middle,
fetch_start, fetch_count,
draw_elts, istart, icount);
}
/**
* Use the cache to prepare the fetch and draw elements, and flush.
*
* When spoken is TRUE, ispoken replaces istart; When close is TRUE, iclose is
* appended.
*/
static inline void
CONCAT2(vsplit_segment_cache_, ELT_TYPE)(struct vsplit_frontend *vsplit,
unsigned flags,
unsigned istart, unsigned icount,
bool spoken, unsigned ispoken,
bool close, unsigned iclose)
{
struct draw_context *draw = vsplit->draw;
const ELT_TYPE *ib = (const ELT_TYPE *) draw->pt.user.elts;
const int ibias = draw->pt.user.eltBias;
assert(icount + !!close <= vsplit->segment_size);
vsplit_clear_cache(vsplit);
spoken = !!spoken;
if (ibias == 0) {
if (spoken)
ADD_CACHE(vsplit, ib, 0, ispoken, 0);
for (unsigned i = spoken; i < icount; i++) {
ADD_CACHE(vsplit, ib, istart, i, 0);
}
if (close)
ADD_CACHE(vsplit, ib, 0, iclose, 0);
} else {
if (spoken)
ADD_CACHE(vsplit, ib, 0, ispoken, ibias);
for (unsigned i = spoken; i < icount; i++)
ADD_CACHE(vsplit, ib, istart, i, ibias);
if (close)
ADD_CACHE(vsplit, ib, 0, iclose, ibias);
}
vsplit_flush_cache(vsplit, istart, flags);
}
static void
CONCAT2(vsplit_segment_simple_, ELT_TYPE)(struct vsplit_frontend *vsplit,
unsigned flags,
unsigned istart,
unsigned icount)
{
CONCAT2(vsplit_segment_cache_, ELT_TYPE)(vsplit,
flags, istart, icount, false, 0, false, 0);
}
static void
CONCAT2(vsplit_segment_loop_, ELT_TYPE)(struct vsplit_frontend *vsplit,
unsigned flags,
unsigned istart,
unsigned icount,
unsigned i0)
{
const bool close_loop = ((flags) == DRAW_SPLIT_BEFORE);
CONCAT2(vsplit_segment_cache_, ELT_TYPE)(vsplit,
flags, istart, icount, false, 0, close_loop, i0);
}
static void
CONCAT2(vsplit_segment_fan_, ELT_TYPE)(struct vsplit_frontend *vsplit,
unsigned flags,
unsigned istart,
unsigned icount,
unsigned i0)
{
const bool use_spoken = (((flags) & DRAW_SPLIT_BEFORE) != 0);
CONCAT2(vsplit_segment_cache_, ELT_TYPE)(vsplit,
flags, istart, icount, use_spoken, i0, false, 0);
}
#define LOCAL_VARS \
struct vsplit_frontend *vsplit = (struct vsplit_frontend *) frontend; \
const enum mesa_prim prim = vsplit->prim; \
const unsigned max_count_simple = vsplit->segment_size; \
const unsigned max_count_loop = vsplit->segment_size - 1; \
const unsigned max_count_fan = vsplit->segment_size;
#define PRIMITIVE(istart, icount) \
CONCAT2(vsplit_primitive_, ELT_TYPE)(vsplit, istart, icount)
#else /* ELT_TYPE */
static void
vsplit_segment_simple_linear(struct vsplit_frontend *vsplit, unsigned flags,
unsigned istart, unsigned icount)
{
assert(icount <= vsplit->max_vertices);
vsplit->middle->run_linear(vsplit->middle, istart, icount, flags);
}
static void
vsplit_segment_loop_linear(struct vsplit_frontend *vsplit, unsigned flags,
unsigned istart, unsigned icount, unsigned i0)
{
bool close_loop = (flags == DRAW_SPLIT_BEFORE);
unsigned nr;
assert(icount + !!close_loop <= vsplit->segment_size);
/* need to draw the sections of the line loop as line strips */
flags |= DRAW_LINE_LOOP_AS_STRIP;
if (close_loop) {
for (nr = 0; nr < icount; nr++)
vsplit->fetch_elts[nr] = istart + nr;
vsplit->fetch_elts[nr++] = i0;
vsplit->middle->run(vsplit->middle, istart, vsplit->fetch_elts, nr,
vsplit->identity_draw_elts, nr, flags);
} else {
vsplit->middle->run_linear(vsplit->middle, istart, icount, flags);
}
}
static void
vsplit_segment_fan_linear(struct vsplit_frontend *vsplit, unsigned flags,
unsigned istart, unsigned icount, unsigned i0)
{
bool use_spoken = ((flags & DRAW_SPLIT_BEFORE) != 0);
unsigned nr = 0;
assert(icount <= vsplit->segment_size);
if (use_spoken) {
/* replace istart by i0 */
vsplit->fetch_elts[nr++] = i0;
for (unsigned i = 1 ; i < icount; i++)
vsplit->fetch_elts[nr++] = istart + i;
vsplit->middle->run(vsplit->middle, istart, vsplit->fetch_elts, nr,
vsplit->identity_draw_elts, nr, flags);
} else {
vsplit->middle->run_linear(vsplit->middle, istart, icount, flags);
}
}
#define LOCAL_VARS \
struct vsplit_frontend *vsplit = (struct vsplit_frontend *) frontend; \
const enum mesa_prim prim = vsplit->prim; \
const unsigned max_count_simple = vsplit->max_vertices; \
const unsigned max_count_loop = vsplit->segment_size - 1; \
const unsigned max_count_fan = vsplit->segment_size;
#define PRIMITIVE(istart, icount) false
#define ELT_TYPE linear
#endif /* ELT_TYPE */
#define FUNC_VARS \
struct draw_pt_front_end *frontend, \
unsigned start, \
unsigned count
#define SEGMENT_SIMPLE(flags, istart, icount) \
CONCAT2(vsplit_segment_simple_, ELT_TYPE)(vsplit, flags, istart, icount)
#define SEGMENT_LOOP(flags, istart, icount, i0) \
CONCAT2(vsplit_segment_loop_, ELT_TYPE)(vsplit, flags, istart, icount, i0)
#define SEGMENT_FAN(flags, istart, icount, i0) \
CONCAT2(vsplit_segment_fan_, ELT_TYPE)(vsplit, flags, istart, icount, i0)
#include "draw_split_tmp.h"
#undef ELT_TYPE
#undef ADD_CACHE
@@ -0,0 +1,31 @@
#define FUNC_VARS \
struct pt_so_emit *so, \
const struct draw_prim_info *input_prims, \
const struct draw_vertex_info *input_verts, \
unsigned start, \
unsigned count
#define FUNC_ENTER \
/* declare more local vars */ \
const enum mesa_prim prim = input_prims->prim; \
const unsigned prim_flags = input_prims->flags; \
const bool quads_flatshade_last = false; \
const bool last_vertex_last = !so->draw->rasterizer->flatshade_first; \
do { \
switch (prim) { \
case MESA_PRIM_LINES_ADJACENCY: \
case MESA_PRIM_LINE_STRIP_ADJACENCY: \
case MESA_PRIM_TRIANGLES_ADJACENCY: \
case MESA_PRIM_TRIANGLE_STRIP_ADJACENCY: \
assert(!"unexpected primitive type in stream output"); \
return; \
default: \
break; \
} \
} while (0)
#define POINT(i0) so_point(so,i0)
#define LINE(flags,i0,i1) so_line(so,i0,i1)
#define TRIANGLE(flags,i0,i1,i2) so_tri(so,i0,i1,i2)
#include "draw_decompose_tmp.h"
+176
View File
@@ -0,0 +1,176 @@
/*
* Mesa 3-D graphics library
*
* Copyright 2008 VMware, Inc.
* Copyright (C) 2010 LunarG Inc.
*
* 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 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.
*/
static void
FUNC(FUNC_VARS)
{
unsigned first, incr;
LOCAL_VARS
/*
* prim, start, count, and max_count_{simple,loop,fan} should have been
* defined
*/
if (0) {
debug_printf("%s: prim 0x%x, start %d, count %d, max_count_simple %d, "
"max_count_loop %d, max_count_fan %d\n",
__func__, prim, start, count, max_count_simple,
max_count_loop, max_count_fan);
}
if (prim == MESA_PRIM_PATCHES) {
first = vsplit->draw->pt.vertices_per_patch;
incr = vsplit->draw->pt.vertices_per_patch;
} else
draw_pt_split_prim(prim, &first, &incr);
/* sanitize primitive length */
count = draw_pt_trim_count(count, first, incr);
if (count < first)
return;
/* try flushing the entire primitive */
if (PRIMITIVE(start, count))
return;
/* must be able to at least flush two complete primitives */
assert(max_count_simple >= first + incr &&
max_count_loop >= first + incr &&
max_count_fan >= first + incr);
/* no splitting required */
if (count <= max_count_simple) {
SEGMENT_SIMPLE(0x0, start, count);
} else {
const unsigned rollback = first - incr;
unsigned flags = DRAW_SPLIT_AFTER, seg_start = 0, seg_max;
/*
* Both count and seg_max below are explicitly trimmed. Because
*
* seg_start = N * (seg_max - rollback) = N' * incr,
*
* we have
*
* remaining = count - seg_start = first + N'' * incr.
*
* That is, remaining is implicitly trimmed.
*/
switch (prim) {
case MESA_PRIM_PATCHES:
case MESA_PRIM_POINTS:
case MESA_PRIM_LINES:
case MESA_PRIM_LINE_STRIP:
case MESA_PRIM_TRIANGLES:
case MESA_PRIM_TRIANGLE_STRIP:
case MESA_PRIM_QUADS:
case MESA_PRIM_QUAD_STRIP:
case MESA_PRIM_LINES_ADJACENCY:
case MESA_PRIM_LINE_STRIP_ADJACENCY:
case MESA_PRIM_TRIANGLES_ADJACENCY:
case MESA_PRIM_TRIANGLE_STRIP_ADJACENCY:
seg_max =
draw_pt_trim_count(MIN2(max_count_simple, count), first, incr);
if (prim == MESA_PRIM_TRIANGLE_STRIP ||
prim == MESA_PRIM_TRIANGLE_STRIP_ADJACENCY) {
/* make sure we flush even number of triangles at a time */
if (seg_max < count && !(((seg_max - first) / incr) & 1))
seg_max -= incr;
}
do {
const unsigned remaining = count - seg_start;
if (remaining > seg_max) {
SEGMENT_SIMPLE(flags, start + seg_start, seg_max);
seg_start += seg_max - rollback;
flags |= DRAW_SPLIT_BEFORE;
} else {
flags &= ~DRAW_SPLIT_AFTER;
SEGMENT_SIMPLE(flags, start + seg_start, remaining);
seg_start += remaining;
}
} while (seg_start < count);
break;
case MESA_PRIM_LINE_LOOP:
seg_max =
draw_pt_trim_count(MIN2(max_count_loop, count), first, incr);
do {
const unsigned remaining = count - seg_start;
if (remaining > seg_max) {
SEGMENT_LOOP(flags, start + seg_start, seg_max, start);
seg_start += seg_max - rollback;
flags |= DRAW_SPLIT_BEFORE;
} else {
flags &= ~DRAW_SPLIT_AFTER;
SEGMENT_LOOP(flags, start + seg_start, remaining, start);
seg_start += remaining;
}
} while (seg_start < count);
break;
case MESA_PRIM_TRIANGLE_FAN:
case MESA_PRIM_POLYGON:
seg_max =
draw_pt_trim_count(MIN2(max_count_fan, count), first, incr);
do {
const unsigned remaining = count - seg_start;
if (remaining > seg_max) {
SEGMENT_FAN(flags, start + seg_start, seg_max, start);
seg_start += seg_max - rollback;
flags |= DRAW_SPLIT_BEFORE;
} else {
flags &= ~DRAW_SPLIT_AFTER;
SEGMENT_FAN(flags, start + seg_start, remaining, start);
seg_start += remaining;
}
} while (seg_start < count);
break;
default:
assert(0);
break;
}
}
}
#undef FUNC
#undef FUNC_VARS
#undef LOCAL_VARS
#undef PRIMITIVE
#undef SEGMENT_SIMPLE
#undef SEGMENT_LOOP
#undef SEGMENT_FAN
+667
View File
@@ -0,0 +1,667 @@
/**************************************************************************
*
* Copyright 2020 Red Hat.
* 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
* 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 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.
*
**************************************************************************/
#include "draw_tess.h"
#if DRAW_LLVM_AVAILABLE
#include "draw_llvm.h"
#endif
#include "tessellator/p_tessellator.h"
#include "nir/nir_to_tgsi_info.h"
#include "util/u_prim.h"
#include "util/u_math.h"
#include "util/u_memory.h"
#include "util/ralloc.h"
#if DRAW_LLVM_AVAILABLE
static inline int
draw_tes_get_input_index(int semantic, int index,
const struct tgsi_shader_info *input_info)
{
int i;
const uint8_t *input_semantic_names = input_info->output_semantic_name;
const uint8_t *input_semantic_indices = input_info->output_semantic_index;
for (i = 0; i < PIPE_MAX_SHADER_OUTPUTS; i++) {
if (input_semantic_names[i] == semantic &&
input_semantic_indices[i] == index)
return i;
}
return -1;
}
#define DEBUG_INPUTS 0
static void
llvm_fetch_tcs_input(struct draw_tess_ctrl_shader *shader,
const struct draw_prim_info *input_prim_info,
unsigned prim_id,
unsigned num_vertices)
{
const float (*input_ptr)[4];
float (*input_data)[32][NUM_TCS_INPUTS][TGSI_NUM_CHANNELS] = &shader->tcs_input->data;
unsigned slot, i;
int vs_slot;
unsigned input_vertex_stride = shader->input_vertex_stride;
input_ptr = shader->input;
for (i = 0; i < num_vertices; i++) {
const float (*input)[4];
int vertex_idx = prim_id * num_vertices + i;
if (input_prim_info->linear == false)
vertex_idx = input_prim_info->elts[vertex_idx];
#if DEBUG_INPUTS
debug_printf("%d) tcs vertex index = %d (prim idx = %d)\n",
i, prim_id, 0);
#endif
input = (const float (*)[4])((const char *)input_ptr + (vertex_idx * input_vertex_stride));
for (slot = 0, vs_slot = 0; slot < shader->info.num_inputs; ++slot) {
vs_slot = draw_tes_get_input_index(
shader->info.input_semantic_name[slot],
shader->info.input_semantic_index[slot],
shader->input_info);
if (vs_slot < 0) {
debug_printf("VS/TCS signature mismatch!\n");
(*input_data)[i][slot][0] = 0;
(*input_data)[i][slot][1] = 0;
(*input_data)[i][slot][2] = 0;
(*input_data)[i][slot][3] = 0;
} else {
(*input_data)[i][slot][0] = input[vs_slot][0];
(*input_data)[i][slot][1] = input[vs_slot][1];
(*input_data)[i][slot][2] = input[vs_slot][2];
(*input_data)[i][slot][3] = input[vs_slot][3];
#if DEBUG_INPUTS
debug_printf("\t\t%p = %f %f %f %f\n", &(*input_data)[i][slot][0],
(*input_data)[i][slot][0],
(*input_data)[i][slot][1],
(*input_data)[i][slot][2],
(*input_data)[i][slot][3]);
#endif
++vs_slot;
}
}
}
}
#define DEBUG_OUTPUTS 0
static void
llvm_store_tcs_output(struct draw_tess_ctrl_shader *shader,
unsigned prim_id,
struct draw_vertex_info *output_verts,
unsigned vert_start)
{
float (*output_ptr)[4];
float (*output_data)[32][PIPE_MAX_SHADER_INPUTS][TGSI_NUM_CHANNELS] = &shader->tcs_output->data;
unsigned slot, i;
unsigned num_vertices = shader->vertices_out;
char *output = (char *)output_verts->verts->data;
output += vert_start * output_verts->stride;
for (i = 0; i < num_vertices; i++) {
#if DEBUG_OUTPUTS
debug_printf("%d) tcs store vertex index = %d (prim idx = %d)\n",
i, prim_id, 0);
#endif
output_ptr = (float(*)[4])(output + (i * output_verts->stride));
for (slot = 0; slot < shader->info.num_outputs; ++slot) {
output_ptr[slot][0] = (*output_data)[i][slot][0];
output_ptr[slot][1] = (*output_data)[i][slot][1];
output_ptr[slot][2] = (*output_data)[i][slot][2];
output_ptr[slot][3] = (*output_data)[i][slot][3];
#if DEBUG_OUTPUTS
debug_printf("\t\t%p = %f %f %f %f\n",
&output_ptr[slot][0],
output_ptr[slot][0],
output_ptr[slot][1],
output_ptr[slot][2],
output_ptr[slot][3]);
#endif
}
}
}
static void
llvm_tcs_run(struct draw_tess_ctrl_shader *shader, uint32_t prim_id)
{
shader->current_variant->jit_func(shader->jit_resources,
shader->tcs_input->data, shader->tcs_output->data, prim_id,
shader->draw->pt.vertices_per_patch, shader->draw->pt.user.viewid);
}
#endif
/**
* Execute tess ctrl shader.
*/
int draw_tess_ctrl_shader_run(struct draw_tess_ctrl_shader *shader,
const struct draw_vertex_info *input_verts,
const struct draw_prim_info *input_prims,
const struct tgsi_shader_info *input_info,
struct draw_vertex_info *output_verts,
struct draw_prim_info *output_prims)
{
const float (*input)[4] = (const float (*)[4])input_verts->verts->data;
unsigned num_outputs = draw_total_tcs_outputs(shader->draw);
unsigned input_stride = input_verts->vertex_size;
unsigned vertex_size = sizeof(struct vertex_header) + num_outputs * 4 * sizeof(float);
unsigned num_patches = input_prims->count / shader->draw->pt.vertices_per_patch;
output_verts->vertex_size = vertex_size;
output_verts->stride = output_verts->vertex_size;
output_verts->verts = NULL;
output_verts->count = 0;
shader->input = input;
shader->input_vertex_stride = input_stride;
shader->input_info = input_info;
output_prims->linear = true;
output_prims->start = input_prims->start;
output_prims->elts = NULL;
output_prims->count = 0;
output_prims->prim = MESA_PRIM_PATCHES;
output_prims->flags = 0;
output_prims->primitive_lengths = NULL;
output_prims->primitive_count = 0;
if (shader->draw->collect_statistics) {
shader->draw->statistics.hs_invocations += num_patches;
}
#if DRAW_LLVM_AVAILABLE
unsigned first_patch = input_prims->start / shader->draw->pt.vertices_per_patch;
for (unsigned i = 0; i < num_patches; i++) {
uint32_t vert_start = output_verts->count;
output_verts->count += shader->vertices_out;
llvm_fetch_tcs_input(shader, input_prims, i, shader->draw->pt.vertices_per_patch);
llvm_tcs_run(shader, first_patch + i);
uint32_t old_verts = util_align_npot(vert_start, 16);
uint32_t new_verts = util_align_npot(output_verts->count, 16);
uint32_t old_size = output_verts->vertex_size * old_verts;
uint32_t new_size = output_verts->vertex_size * new_verts;
output_verts->verts = REALLOC(output_verts->verts, old_size, new_size);
llvm_store_tcs_output(shader, i, output_verts, vert_start);
}
#endif
output_prims->primitive_count = num_patches;
return 0;
}
#if DRAW_LLVM_AVAILABLE
#define DEBUG_INPUTS 0
static void
llvm_fetch_tes_input(struct draw_tess_eval_shader *shader,
const struct draw_prim_info *input_prim_info,
unsigned prim_id,
unsigned num_vertices)
{
const float (*input_ptr)[4];
float (*input_data)[32][PIPE_MAX_SHADER_INPUTS][TGSI_NUM_CHANNELS] = &shader->tes_input->data;
unsigned slot, i;
int vs_slot;
unsigned input_vertex_stride = shader->input_vertex_stride;
input_ptr = shader->input;
for (i = 0; i < num_vertices; i++) {
const float (*input)[4];
int vertex_idx = prim_id * num_vertices + i;
if (input_prim_info->linear == false)
vertex_idx = input_prim_info->elts[vertex_idx];
#if DEBUG_INPUTS
debug_printf("%d) tes vertex index = %d (prim idx = %d)\n",
i, prim_id, 0);
#endif
input = (const float (*)[4])((const char *)input_ptr + (vertex_idx * input_vertex_stride));
for (slot = 0, vs_slot = 0; slot < shader->info.num_inputs; ++slot) {
vs_slot = draw_tes_get_input_index(
shader->info.input_semantic_name[slot],
shader->info.input_semantic_index[slot],
shader->input_info);
if (vs_slot < 0) {
debug_printf("TCS/TES signature mismatch!\n");
(*input_data)[i][slot][0] = 0;
(*input_data)[i][slot][1] = 0;
(*input_data)[i][slot][2] = 0;
(*input_data)[i][slot][3] = 0;
} else {
(*input_data)[i][slot][0] = input[vs_slot][0];
(*input_data)[i][slot][1] = input[vs_slot][1];
(*input_data)[i][slot][2] = input[vs_slot][2];
(*input_data)[i][slot][3] = input[vs_slot][3];
#if DEBUG_INPUTS
debug_printf("\t\t%p = %f %f %f %f\n",
&input[vs_slot][0],
(*input_data)[i][slot][0],
(*input_data)[i][slot][1],
(*input_data)[i][slot][2],
(*input_data)[i][slot][3]);
#endif
++vs_slot;
}
}
}
}
static void
llvm_fetch_tess_factors(struct draw_tess_eval_shader *shader,
unsigned patch_id,
unsigned num_vertices,
struct pipe_tessellation_factors *factors)
{
int outer_slot = draw_tes_get_input_index(
TGSI_SEMANTIC_TESSOUTER, 0, shader->input_info);
int inner_slot = draw_tes_get_input_index(
TGSI_SEMANTIC_TESSINNER, 0, shader->input_info);
const float (*input_ptr)[4];
const float (*input)[4];
input_ptr = shader->input;
input = (const float (*)[4])((const char *)input_ptr + ((patch_id * num_vertices) * shader->input_vertex_stride));
if (outer_slot != -1) {
for (unsigned i = 0; i < 4; i++)
factors->outer_tf[i] = input[outer_slot][i];
} else {
for (unsigned i = 0; i < 4; i++)
factors->outer_tf[i] = shader->draw->default_outer_tess_level[i];
}
if (inner_slot != -1) {
for (unsigned i = 0; i < 2; i++)
factors->inner_tf[i] = input[inner_slot][i];
} else {
for (unsigned i = 0; i < 2; i++)
factors->inner_tf[i] = shader->draw->default_inner_tess_level[i];
}
}
static void
llvm_tes_run(struct draw_tess_eval_shader *shader,
uint32_t prim_id,
uint32_t patch_vertices_in,
struct pipe_tessellator_data *tess_data,
struct pipe_tessellation_factors *tess_factors,
struct vertex_header *output)
{
shader->current_variant->jit_func(shader->jit_resources,
shader->tes_input->data, output, prim_id,
tess_data->num_domain_points, tess_data->domain_points_u, tess_data->domain_points_v,
tess_factors->outer_tf, tess_factors->inner_tf, patch_vertices_in,
shader->draw->pt.user.viewid);
}
#endif
/**
* Execute tess eval shader.
*/
int draw_tess_eval_shader_run(struct draw_tess_eval_shader *shader,
unsigned num_input_vertices_per_patch,
const struct draw_vertex_info *input_verts,
const struct draw_prim_info *input_prims,
const struct tgsi_shader_info *input_info,
struct draw_vertex_info *output_verts,
struct draw_prim_info *output_prims,
uint32_t **patch_lengths,
uint16_t **elts_out)
{
const float (*input)[4] = (const float (*)[4])input_verts->verts->data;
unsigned num_outputs = draw_total_tes_outputs(shader->draw);
unsigned input_stride = input_verts->vertex_size;
unsigned vertex_size = sizeof(struct vertex_header) + num_outputs * 4 * sizeof(float);
uint16_t *elts = NULL;
output_verts->vertex_size = vertex_size;
output_verts->stride = output_verts->vertex_size;
output_verts->count = 0;
output_verts->verts = NULL;
output_prims->linear = false;
output_prims->start = 0;
output_prims->elts = NULL;
output_prims->count = 0;
output_prims->prim = get_tes_output_prim(shader);
output_prims->flags = 0;
output_prims->primitive_lengths = NULL;
output_prims->primitive_count = 0;
if (patch_lengths) {
*patch_lengths = MALLOC(input_prims->primitive_count * sizeof(uint32_t));
}
shader->input = input;
shader->input_vertex_stride = input_stride;
shader->input_info = input_info;
#if DRAW_LLVM_AVAILABLE
struct pipe_tessellation_factors factors;
struct pipe_tessellator_data data = { 0 };
struct pipe_tessellator *ptess = p_tess_init(shader->prim_mode,
shader->spacing,
!shader->vertex_order_cw,
shader->point_mode);
unsigned first_patch = input_prims->start / shader->draw->pt.vertices_per_patch;
for (unsigned i = 0; i < input_prims->primitive_count; i++) {
uint32_t vert_start = output_verts->count;
uint32_t prim_start = output_prims->primitive_count;
uint32_t elt_start = output_prims->count;
llvm_fetch_tess_factors(shader, i, num_input_vertices_per_patch, &factors);
/**
* Tessellate with the factors for this primitive.
* Make sure subnormals are not flushed to zero during tessellation.
* This is the behavior required by D3D11. OpenGL doesn't care.
*/
unsigned fpstate = util_fpstate_get();
util_fpstate_set(shader->draw->fpstate); /* do not flush subnormals */
p_tessellate(ptess, &factors, &data);
util_fpstate_set(fpstate); /* flush subnormals again */
if (data.num_domain_points == 0)
continue;
uint32_t old_verts = vert_start;
uint32_t new_verts = vert_start + util_align_npot(data.num_domain_points, 4);
uint32_t old_size = output_verts->vertex_size * old_verts;
uint32_t new_size = output_verts->vertex_size * new_verts;
output_verts->verts = REALLOC(output_verts->verts, old_size, new_size);
output_verts->count += data.num_domain_points;
output_prims->count += data.num_indices;
elts = REALLOC(elts, elt_start * sizeof(uint16_t),
output_prims->count * sizeof(uint16_t));
for (uint32_t i = 0; i < data.num_indices; i++)
elts[elt_start + i] = vert_start + data.indices[i];
llvm_fetch_tes_input(shader, input_prims, i, num_input_vertices_per_patch);
/* run once per primitive? */
char *output = (char *)output_verts->verts;
output += vert_start * vertex_size;
llvm_tes_run(shader, first_patch + i, num_input_vertices_per_patch, &data, &factors, (struct vertex_header *)output);
if (shader->draw->collect_statistics) {
shader->draw->statistics.ds_invocations += data.num_domain_points;
}
uint32_t prim_len = u_prim_vertex_count(output_prims->prim)->min;
uint32_t prims_per_patch = data.num_indices / prim_len;
output_prims->primitive_count += prims_per_patch;
if (patch_lengths) {
(*patch_lengths)[i] = prims_per_patch;
}
output_prims->primitive_lengths = REALLOC(output_prims->primitive_lengths, prim_start * sizeof(uint32_t),
output_prims->primitive_count * sizeof(uint32_t));
for (uint32_t i = prim_start; i < output_prims->primitive_count; i++) {
output_prims->primitive_lengths[i] = prim_len;
}
}
p_tess_destroy(ptess);
#endif
*elts_out = elts;
output_prims->elts = elts;
return 0;
}
struct draw_tess_ctrl_shader *
draw_create_tess_ctrl_shader(struct draw_context *draw,
const struct pipe_shader_state *state)
{
#if DRAW_LLVM_AVAILABLE
bool use_llvm = draw->llvm != NULL;
struct llvm_tess_ctrl_shader *llvm_tcs = NULL;
#endif
struct draw_tess_ctrl_shader *tcs;
#if DRAW_LLVM_AVAILABLE
if (use_llvm) {
llvm_tcs = CALLOC_STRUCT(llvm_tess_ctrl_shader);
if (!llvm_tcs)
return NULL;
tcs = &llvm_tcs->base;
list_inithead(&llvm_tcs->variants.list);
} else
#endif
{
tcs = CALLOC_STRUCT(draw_tess_ctrl_shader);
}
if (!tcs)
return NULL;
tcs->draw = draw;
tcs->state = *state;
nir_tgsi_scan_shader(state->ir.nir, &tcs->info, true);
tcs->vector_length = 4;
tcs->vertices_out = tcs->info.properties[TGSI_PROPERTY_TCS_VERTICES_OUT];
#if DRAW_LLVM_AVAILABLE
if (use_llvm) {
tcs->tcs_input = align_malloc(sizeof(struct draw_tcs_inputs), 16);
memset(tcs->tcs_input, 0, sizeof(struct draw_tcs_inputs));
tcs->tcs_output = align_malloc(sizeof(struct draw_tcs_outputs), 16);
memset(tcs->tcs_output, 0, sizeof(struct draw_tcs_outputs));
tcs->jit_resources = &draw->llvm->jit_resources[MESA_SHADER_TESS_CTRL];
llvm_tcs->variant_key_size =
draw_tcs_llvm_variant_key_size(
tcs->info.file_max[TGSI_FILE_SAMPLER]+1,
tcs->info.file_max[TGSI_FILE_SAMPLER_VIEW]+1,
tcs->info.file_max[TGSI_FILE_IMAGE]+1);
}
#endif
return tcs;
}
void draw_bind_tess_ctrl_shader(struct draw_context *draw,
struct draw_tess_ctrl_shader *dtcs)
{
draw_do_flush(draw, DRAW_FLUSH_STATE_CHANGE);
if (dtcs) {
draw->tcs.tess_ctrl_shader = dtcs;
} else {
draw->tcs.tess_ctrl_shader = NULL;
}
}
void draw_delete_tess_ctrl_shader(struct draw_context *draw,
struct draw_tess_ctrl_shader *dtcs)
{
if (!dtcs)
return;
#if DRAW_LLVM_AVAILABLE
if (draw->llvm) {
struct llvm_tess_ctrl_shader *shader = llvm_tess_ctrl_shader(dtcs);
struct draw_tcs_llvm_variant_list_item *li, *next;
LIST_FOR_EACH_ENTRY_SAFE(li, next, &shader->variants.list, list) {
draw_tcs_llvm_destroy_variant(li->base);
}
assert(shader->variants_cached == 0);
align_free(dtcs->tcs_input);
align_free(dtcs->tcs_output);
}
#endif
if (dtcs->state.type == PIPE_SHADER_IR_NIR && dtcs->state.ir.nir)
ralloc_free(dtcs->state.ir.nir);
FREE(dtcs);
}
#if DRAW_LLVM_AVAILABLE
void draw_tcs_set_current_variant(struct draw_tess_ctrl_shader *shader,
struct draw_tcs_llvm_variant *variant)
{
shader->current_variant = variant;
}
#endif
struct draw_tess_eval_shader *
draw_create_tess_eval_shader(struct draw_context *draw,
const struct pipe_shader_state *state)
{
#if DRAW_LLVM_AVAILABLE
bool use_llvm = draw->llvm != NULL;
struct llvm_tess_eval_shader *llvm_tes = NULL;
#endif
struct draw_tess_eval_shader *tes;
#if DRAW_LLVM_AVAILABLE
if (use_llvm) {
llvm_tes = CALLOC_STRUCT(llvm_tess_eval_shader);
if (!llvm_tes)
return NULL;
tes = &llvm_tes->base;
list_inithead(&llvm_tes->variants.list);
} else
#endif
{
tes = CALLOC_STRUCT(draw_tess_eval_shader);
}
if (!tes)
return NULL;
tes->draw = draw;
tes->state = *state;
nir_tgsi_scan_shader(state->ir.nir, &tes->info, true);
tes->prim_mode = tes->info.properties[TGSI_PROPERTY_TES_PRIM_MODE];
tes->spacing = tes->info.properties[TGSI_PROPERTY_TES_SPACING];
tes->vertex_order_cw = tes->info.properties[TGSI_PROPERTY_TES_VERTEX_ORDER_CW];
tes->point_mode = tes->info.properties[TGSI_PROPERTY_TES_POINT_MODE];
tes->vector_length = 4;
tes->position_output = -1;
bool found_clipvertex = false;
for (unsigned i = 0; i < tes->info.num_outputs; i++) {
if (tes->info.output_semantic_name[i] == TGSI_SEMANTIC_POSITION &&
tes->info.output_semantic_index[i] == 0)
tes->position_output = i;
if (tes->info.output_semantic_name[i] == TGSI_SEMANTIC_VIEWPORT_INDEX)
tes->viewport_index_output = i;
if (tes->info.output_semantic_name[i] == TGSI_SEMANTIC_CLIPVERTEX &&
tes->info.output_semantic_index[i] == 0) {
found_clipvertex = true;
tes->clipvertex_output = i;
}
if (tes->info.output_semantic_name[i] == TGSI_SEMANTIC_CLIPDIST) {
assert(tes->info.output_semantic_index[i] <
PIPE_MAX_CLIP_OR_CULL_DISTANCE_ELEMENT_COUNT);
tes->ccdistance_output[tes->info.output_semantic_index[i]] = i;
}
}
if (!found_clipvertex)
tes->clipvertex_output = tes->position_output;
#if DRAW_LLVM_AVAILABLE
if (use_llvm) {
tes->tes_input = align_malloc(sizeof(struct draw_tes_inputs), 16);
memset(tes->tes_input, 0, sizeof(struct draw_tes_inputs));
tes->jit_resources = &draw->llvm->jit_resources[MESA_SHADER_TESS_EVAL];
llvm_tes->variant_key_size =
draw_tes_llvm_variant_key_size(
tes->info.file_max[TGSI_FILE_SAMPLER]+1,
tes->info.file_max[TGSI_FILE_SAMPLER_VIEW]+1,
tes->info.file_max[TGSI_FILE_IMAGE]+1);
}
#endif
return tes;
}
void draw_bind_tess_eval_shader(struct draw_context *draw,
struct draw_tess_eval_shader *dtes)
{
draw_do_flush(draw, DRAW_FLUSH_STATE_CHANGE);
if (dtes) {
draw->tes.tess_eval_shader = dtes;
draw->tes.num_tes_outputs = dtes->info.num_outputs;
draw->tes.position_output = dtes->position_output;
draw->tes.clipvertex_output = dtes->clipvertex_output;
} else {
draw->tes.tess_eval_shader = NULL;
}
}
void draw_delete_tess_eval_shader(struct draw_context *draw,
struct draw_tess_eval_shader *dtes)
{
if (!dtes)
return;
#if DRAW_LLVM_AVAILABLE
if (draw->llvm) {
struct llvm_tess_eval_shader *shader = llvm_tess_eval_shader(dtes);
struct draw_tes_llvm_variant_list_item *li, *next;
LIST_FOR_EACH_ENTRY_SAFE(li, next, &shader->variants.list, list) {
draw_tes_llvm_destroy_variant(li->base);
}
assert(shader->variants_cached == 0);
align_free(dtes->tes_input);
}
#endif
if (dtes->state.type == PIPE_SHADER_IR_NIR && dtes->state.ir.nir)
ralloc_free(dtes->state.ir.nir);
FREE(dtes);
}
#if DRAW_LLVM_AVAILABLE
void draw_tes_set_current_variant(struct draw_tess_eval_shader *shader,
struct draw_tes_llvm_variant *variant)
{
shader->current_variant = variant;
}
#endif
enum mesa_prim get_tes_output_prim(struct draw_tess_eval_shader *shader)
{
if (shader->point_mode)
return MESA_PRIM_POINTS;
else if (shader->prim_mode == MESA_PRIM_LINES)
return MESA_PRIM_LINES;
else
return MESA_PRIM_TRIANGLES;
}
+130
View File
@@ -0,0 +1,130 @@
/**************************************************************************
*
* Copyright 2020 Red Hat.
* 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
* 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 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.
*
**************************************************************************/
#ifndef DRAW_TESS_H
#define DRAW_TESS_H
#include "draw_context.h"
#include "draw_private.h"
#include "tgsi/tgsi_scan.h"
struct draw_context;
#if DRAW_LLVM_AVAILABLE
#define NUM_PATCH_INPUTS 32
#define NUM_TCS_INPUTS (PIPE_MAX_SHADER_INPUTS - NUM_PATCH_INPUTS)
struct draw_tcs_inputs {
/* num vertices per prim */
float data[32][NUM_TCS_INPUTS][4];
};
struct draw_tcs_outputs {
/* num vertices per prim */
float data[32][PIPE_MAX_SHADER_INPUTS][4];
};
struct draw_tes_inputs {
/* num vertices per prim */
float data[32][PIPE_MAX_SHADER_INPUTS][4];
};
#endif
struct draw_tess_ctrl_shader {
struct draw_context *draw;
struct pipe_shader_state state;
struct tgsi_shader_info info;
unsigned vector_length;
unsigned vertices_out;
unsigned input_vertex_stride;
const float (*input)[4];
const struct tgsi_shader_info *input_info;
#if DRAW_LLVM_AVAILABLE
struct draw_tcs_inputs *tcs_input;
struct draw_tcs_outputs *tcs_output;
struct lp_jit_resources *jit_resources;
struct draw_tcs_llvm_variant *current_variant;
#endif
};
struct draw_tess_eval_shader {
struct draw_context *draw;
struct pipe_shader_state state;
struct tgsi_shader_info info;
enum mesa_prim prim_mode;
unsigned spacing;
unsigned vertex_order_cw;
unsigned point_mode;
unsigned position_output;
unsigned viewport_index_output;
unsigned clipvertex_output;
unsigned ccdistance_output[PIPE_MAX_CLIP_OR_CULL_DISTANCE_ELEMENT_COUNT];
unsigned vector_length;
unsigned input_vertex_stride;
const float (*input)[4];
const struct tgsi_shader_info *input_info;
#if DRAW_LLVM_AVAILABLE
struct draw_tes_inputs *tes_input;
struct lp_jit_resources *jit_resources;
struct draw_tes_llvm_variant *current_variant;
#endif
};
enum mesa_prim get_tes_output_prim(struct draw_tess_eval_shader *shader);
int draw_tess_ctrl_shader_run(struct draw_tess_ctrl_shader *shader,
const struct draw_vertex_info *input_verts,
const struct draw_prim_info *input_prim,
const struct tgsi_shader_info *input_info,
struct draw_vertex_info *output_verts,
struct draw_prim_info *output_prims );
int draw_tess_eval_shader_run(struct draw_tess_eval_shader *shader,
unsigned num_input_vertices_per_patch,
const struct draw_vertex_info *input_verts,
const struct draw_prim_info *input_prim,
const struct tgsi_shader_info *input_info,
struct draw_vertex_info *output_verts,
struct draw_prim_info *output_prims,
uint32_t **patch_lengths,
uint16_t **elts_out);
#if DRAW_LLVM_AVAILABLE
void draw_tcs_set_current_variant(struct draw_tess_ctrl_shader *shader,
struct draw_tcs_llvm_variant *variant);
void draw_tes_set_current_variant(struct draw_tess_eval_shader *shader,
struct draw_tes_llvm_variant *variant);
#endif
#endif
+152
View File
@@ -0,0 +1,152 @@
/**************************************************************************
*
* Copyright 2007 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 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 ITS 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.
*
**************************************************************************/
/**
* \file
* Vertex buffer drawing stage.
*
* \author Keith Whitwell <[email protected]>
* \author Jose Fonseca <[email protected]>
*/
#ifndef DRAW_VBUF_H_
#define DRAW_VBUF_H_
#include "util/compiler.h"
#include "pipe/p_defines.h"
struct pipe_rasterizer_state;
struct draw_context;
struct vertex_info;
struct pipe_query_data_pipeline_statistics;
/**
* Interface for hardware vertex buffer rendering.
*/
struct vbuf_render {
/**
* Driver limits. May be tuned lower to improve cache hits on
* index list.
*/
unsigned max_indices;
unsigned max_vertex_buffer_bytes;
/**
* Query if the hardware driver needs assistance for a particular
* combination of rasterizer state and primitive.
*
* Currently optional.
*/
bool (*need_pipeline)(const struct vbuf_render *render,
const struct pipe_rasterizer_state *rasterizer,
unsigned int prim);
/**
* Get the hardware vertex format.
*
* XXX: have this in draw_context instead?
*/
const struct vertex_info *(*get_vertex_info)(struct vbuf_render *);
/**
* Request a destination for vertices.
* Hardware renderers will use ttm memory, others will just malloc
* something.
*/
bool (*allocate_vertices)(struct vbuf_render *,
uint16_t vertex_size,
uint16_t nr_vertices);
void *(*map_vertices)(struct vbuf_render *);
void (*unmap_vertices)(struct vbuf_render *,
uint16_t min_index,
uint16_t max_index);
/**
* Notify the renderer of the current primitive when it changes.
* Must succeed for TRIANGLES, LINES and POINTS. Other prims at
* the discretion of the driver, for the benefit of the passthrough
* path.
*/
void (*set_primitive)(struct vbuf_render *, enum mesa_prim prim);
/**
* Notify the renderer of the current view index.
*/
void (*set_view_index)(struct vbuf_render *, unsigned view_index);
/**
* Draw indexed primitives. Note that indices are ushort. The driver
* must complete this call, if necessary splitting the index list itself.
*/
void (*draw_elements)(struct vbuf_render *,
const uint16_t *indices,
unsigned nr_indices);
/* Draw non-indexed primitives.
*/
void (*draw_arrays)(struct vbuf_render *,
unsigned start,
unsigned nr);
/**
* Called when vbuf is done with this set of vertices:
*/
void (*release_vertices)(struct vbuf_render *);
void (*destroy)(struct vbuf_render *);
/**
* Called after writing data to the stream out buffers
*/
void (*set_stream_output_info)(struct vbuf_render *vbufr,
unsigned stream,
unsigned primitive_count,
unsigned primitive_generated);
/**
* Called after all relevant statistics have been accumulated.
*/
void (*pipeline_statistics)(
struct vbuf_render *vbufr,
const struct pipe_query_data_pipeline_statistics *stats);
};
struct draw_stage *
draw_vbuf_stage(struct draw_context *draw,
struct vbuf_render *render);
#endif /*DRAW_VBUF_H_*/
+113
View File
@@ -0,0 +1,113 @@
/**************************************************************************
*
* Copyright 2007 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 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 ITS 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.
*
**************************************************************************/
/*
* Functions for specifying the post-transformation vertex layout.
*
* Author:
* Brian Paul
* Keith Whitwell
*/
#include "draw/draw_private.h"
#include "draw/draw_vertex.h"
/**
* Compute the size of a vertex, in dwords/floats, to update the
* vinfo->size field.
*/
void
draw_compute_vertex_size(struct vertex_info *vinfo)
{
vinfo->size = 0;
for (unsigned i = 0; i < vinfo->num_attribs; i++)
vinfo->size += draw_translate_vinfo_size(vinfo->attrib[i].emit);
assert(vinfo->size % 4 == 0);
/* in dwords */
vinfo->size /= 4;
}
void
draw_dump_emitted_vertex(const struct vertex_info *vinfo, const uint8_t *data)
{
for (unsigned i = 0; i < vinfo->num_attribs; i++) {
switch (vinfo->attrib[i].emit) {
case EMIT_OMIT:
debug_printf("EMIT_OMIT:");
break;
case EMIT_1F:
debug_printf("EMIT_1F:\t");
debug_printf("%f ", *(float *)data); data += sizeof(float);
break;
case EMIT_1F_PSIZE:
debug_printf("EMIT_1F_PSIZE:\t");
debug_printf("%f ", *(float *)data); data += sizeof(float);
break;
case EMIT_2F:
debug_printf("EMIT_2F:\t");
debug_printf("%f ", *(float *)data); data += sizeof(float);
debug_printf("%f ", *(float *)data); data += sizeof(float);
break;
case EMIT_3F:
debug_printf("EMIT_3F:\t");
debug_printf("%f ", *(float *)data); data += sizeof(float);
debug_printf("%f ", *(float *)data); data += sizeof(float);
debug_printf("%f ", *(float *)data); data += sizeof(float);
data += sizeof(float);
break;
case EMIT_4F:
debug_printf("EMIT_4F:\t");
debug_printf("%f ", *(float *)data); data += sizeof(float);
debug_printf("%f ", *(float *)data); data += sizeof(float);
debug_printf("%f ", *(float *)data); data += sizeof(float);
debug_printf("%f ", *(float *)data); data += sizeof(float);
break;
case EMIT_4UB:
debug_printf("EMIT_4UB:\t");
debug_printf("%u ", *data++);
debug_printf("%u ", *data++);
debug_printf("%u ", *data++);
debug_printf("%u ", *data++);
break;
case EMIT_4UB_BGRA:
debug_printf("EMIT_4UB_BGRA:\t");
debug_printf("%u ", *data++);
debug_printf("%u ", *data++);
debug_printf("%u ", *data++);
debug_printf("%u ", *data++);
break;
default:
assert(0);
}
debug_printf("\n");
}
debug_printf("\n");
}
+195
View File
@@ -0,0 +1,195 @@
/**************************************************************************
*
* Copyright 2007 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 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 ITS 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.
*
**************************************************************************/
/**
* Post-transform vertex format info. The vertex_info struct is used by
* the draw_vbuf code to emit hardware-specific vertex layouts into hw
* vertex buffers.
*
* Author:
* Brian Paul
*/
#ifndef DRAW_VERTEX_H
#define DRAW_VERTEX_H
#include "util/compiler.h"
#include "pipe/p_state.h"
#include "util/u_debug.h"
#include "util/u_memory.h"
#define DRAW_ATTR_NONEXIST 255
/**
* Vertex attribute emit modes
*/
enum attrib_emit {
EMIT_OMIT, /**< don't emit the attribute */
EMIT_1F,
EMIT_1F_PSIZE, /**< insert constant point size */
EMIT_2F,
EMIT_3F,
EMIT_4F,
EMIT_4UB, /**< is RGBA like the rest */
EMIT_4UB_BGRA
};
/**
* Information about hardware/rasterization vertex layout.
*/
struct vertex_info
{
unsigned num_attribs;
unsigned size; /**< total vertex size in dwords */
/* Keep this small and at the end of the struct to allow quick
* memcmp() comparisons.
*/
struct {
unsigned emit:8; /**< EMIT_x */
unsigned src_index:8; /**< map to post-xform attribs */
} attrib[PIPE_MAX_SHADER_OUTPUTS];
};
static inline size_t
draw_vinfo_size(const struct vertex_info *a)
{
return offsetof(const struct vertex_info, attrib[a->num_attribs]);
}
static inline int
draw_vinfo_compare(const struct vertex_info *a,
const struct vertex_info *b)
{
size_t sizea = draw_vinfo_size(a);
return memcmp(a, b, sizea);
}
static inline void
draw_vinfo_copy(struct vertex_info *dst,
const struct vertex_info *src)
{
size_t size = draw_vinfo_size(src);
memcpy(dst, src, size);
}
/**
* Add another attribute to the given vertex_info object.
* \param src_index indicates which post-transformed vertex attrib slot
* corresponds to this attribute.
* \return slot in which the attribute was added
*/
static inline uint
draw_emit_vertex_attr(struct vertex_info *vinfo,
enum attrib_emit emit,
int src_index)
{
const unsigned n = vinfo->num_attribs;
/* If the src_index is negative, meaning it hasn't been found
* we'll assign it all zeros later - set to DRAW_ATTR_NONEXIST */
if (src_index < 0) {
src_index = DRAW_ATTR_NONEXIST;
}
assert(n < ARRAY_SIZE(vinfo->attrib));
vinfo->attrib[n].emit = emit;
vinfo->attrib[n].src_index = src_index;
vinfo->num_attribs++;
return n;
}
void
draw_compute_vertex_size(struct vertex_info *vinfo);
void
draw_dump_emitted_vertex(const struct vertex_info *vinfo,
const uint8_t *data);
static inline enum pipe_format
draw_translate_vinfo_format(enum attrib_emit emit)
{
switch (emit) {
case EMIT_OMIT:
return PIPE_FORMAT_NONE;
case EMIT_1F:
case EMIT_1F_PSIZE:
return PIPE_FORMAT_R32_FLOAT;
case EMIT_2F:
return PIPE_FORMAT_R32G32_FLOAT;
case EMIT_3F:
return PIPE_FORMAT_R32G32B32_FLOAT;
case EMIT_4F:
return PIPE_FORMAT_R32G32B32A32_FLOAT;
case EMIT_4UB:
return PIPE_FORMAT_R8G8B8A8_UNORM;
case EMIT_4UB_BGRA:
return PIPE_FORMAT_B8G8R8A8_UNORM;
default:
assert(!"unexpected format");
return PIPE_FORMAT_NONE;
}
}
static inline unsigned
draw_translate_vinfo_size(enum attrib_emit emit)
{
switch (emit) {
case EMIT_OMIT:
return 0;
case EMIT_1F:
case EMIT_1F_PSIZE:
return 1 * sizeof(float);
case EMIT_2F:
return 2 * sizeof(float);
case EMIT_3F:
return 3 * sizeof(float);
case EMIT_4F:
return 4 * sizeof(float);
case EMIT_4UB:
return 4 * sizeof(unsigned char);
case EMIT_4UB_BGRA:
return 4 * sizeof(unsigned char);
default:
assert(!"unexpected format");
return 0;
}
}
#endif /* DRAW_VERTEX_H */
@@ -0,0 +1,48 @@
/**************************************************************************
*
* Copyright 2007 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 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 ITS 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 DRAW_VERTEX_HEADER_H
#define DRAW_VERTEX_HEADER_H
/** Sum of frustum planes and user-defined planes */
#define DRAW_TOTAL_CLIP_PLANES (6 + PIPE_MAX_CLIP_PLANES)
/**
* Basic vertex info. Used to represent vertices after VS (through GS, TESS,
* etc.) to vbuf output.
*/
struct vertex_header {
unsigned clipmask:DRAW_TOTAL_CLIP_PLANES;
unsigned edgeflag:1;
unsigned pad:1;
unsigned vertex_id:16;
float clip_pos[4];
float data[][4]; // the vertex attributes
};
#endif
+268
View File
@@ -0,0 +1,268 @@
/**************************************************************************
*
* Copyright 2007 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 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 ITS 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.
*
**************************************************************************/
/*
* Authors:
* Keith Whitwell <[email protected]>
* Brian Paul
*/
#include "util/u_math.h"
#include "util/u_memory.h"
#include "pipe/p_shader_tokens.h"
#include "pipe/p_context.h"
#include "pipe/p_screen.h"
#include "draw_private.h"
#include "draw_context.h"
#include "draw_vs.h"
#include "translate/translate.h"
#include "translate/translate_cache.h"
#include "tgsi/tgsi_dump.h"
#include "tgsi/tgsi_exec.h"
#include "tgsi/tgsi_ureg.h"
#include "nir/nir_to_tgsi.h"
DEBUG_GET_ONCE_BOOL_OPTION(gallium_dump_vs, "GALLIUM_DUMP_VS", false)
struct draw_vertex_shader *
draw_create_vertex_shader(struct draw_context *draw,
const struct pipe_shader_state *shader)
{
struct draw_vertex_shader *vs = NULL;
struct pipe_shader_state state = *shader;
if (draw->dump_vs) {
tgsi_dump(shader->tokens, 0);
}
#if DRAW_LLVM_AVAILABLE
bool is_allocated = false;
if (draw->pt.middle.llvm) {
struct pipe_screen *screen = draw->pipe->screen;
if (shader->type == PIPE_SHADER_IR_NIR &&
!screen->shader_caps[MESA_SHADER_VERTEX].integers) {
state.type = PIPE_SHADER_IR_TGSI;
state.tokens = nir_to_tgsi(shader->ir.nir, screen);
is_allocated = true;
}
vs = draw_create_vs_llvm(draw, &state);
}
#endif
if (!vs) {
vs = draw_create_vs_exec(draw, &state);
}
#if DRAW_LLVM_AVAILABLE
if (is_allocated) {
ureg_free_tokens(state.tokens);
}
#endif
if (vs) {
bool found_clipvertex = false;
vs->position_output = -1;
for (unsigned i = 0; i < vs->info.num_outputs; i++) {
if (vs->info.output_semantic_name[i] == TGSI_SEMANTIC_POSITION &&
vs->info.output_semantic_index[i] == 0) {
vs->position_output = i;
} else if (vs->info.output_semantic_name[i] == TGSI_SEMANTIC_EDGEFLAG &&
vs->info.output_semantic_index[i] == 0) {
vs->edgeflag_output = i;
} else if (vs->info.output_semantic_name[i] == TGSI_SEMANTIC_CLIPVERTEX &&
vs->info.output_semantic_index[i] == 0) {
found_clipvertex = true;
vs->clipvertex_output = i;
} else if (vs->info.output_semantic_name[i] == TGSI_SEMANTIC_VIEWPORT_INDEX) {
vs->viewport_index_output = i;
} else if (vs->info.output_semantic_name[i] == TGSI_SEMANTIC_CLIPDIST) {
assert(vs->info.output_semantic_index[i] <
PIPE_MAX_CLIP_OR_CULL_DISTANCE_ELEMENT_COUNT);
vs->ccdistance_output[vs->info.output_semantic_index[i]] = i;
}
}
if (!found_clipvertex)
vs->clipvertex_output = vs->position_output;
}
assert(vs);
return vs;
}
void
draw_bind_vertex_shader(struct draw_context *draw,
struct draw_vertex_shader *dvs)
{
draw_do_flush(draw, DRAW_FLUSH_STATE_CHANGE);
if (dvs) {
draw->vs.vertex_shader = dvs;
draw->vs.num_vs_outputs = dvs->info.num_outputs;
draw->vs.position_output = dvs->position_output;
draw->vs.edgeflag_output = dvs->edgeflag_output;
draw->vs.clipvertex_output = dvs->clipvertex_output;
draw->vs.ccdistance_output[0] = dvs->ccdistance_output[0];
draw->vs.ccdistance_output[1] = dvs->ccdistance_output[1];
dvs->prepare(dvs, draw);
draw_update_clip_flags(draw);
draw_update_viewport_flags(draw);
} else {
draw->vs.vertex_shader = NULL;
draw->vs.num_vs_outputs = 0;
}
}
void
draw_delete_vertex_shader(struct draw_context *draw,
struct draw_vertex_shader *dvs)
{
for (unsigned i = 0; i < dvs->nr_variants; i++)
dvs->variant[i]->destroy(dvs->variant[i]);
dvs->nr_variants = 0;
dvs->delete(dvs);
}
bool
draw_vs_init(struct draw_context *draw)
{
draw->dump_vs = debug_get_option_gallium_dump_vs();
if (!draw->llvm) {
draw->vs.tgsi.machine = tgsi_exec_machine_create(MESA_SHADER_VERTEX);
if (!draw->vs.tgsi.machine)
return false;
}
draw->vs.emit_cache = translate_cache_create();
if (!draw->vs.emit_cache)
return false;
draw->vs.fetch_cache = translate_cache_create();
if (!draw->vs.fetch_cache)
return false;
return true;
}
void
draw_vs_destroy(struct draw_context *draw)
{
if (draw->vs.fetch_cache)
translate_cache_destroy(draw->vs.fetch_cache);
if (draw->vs.emit_cache)
translate_cache_destroy(draw->vs.emit_cache);
if (!draw->llvm)
tgsi_exec_machine_destroy(draw->vs.tgsi.machine);
}
struct draw_vs_variant *
draw_vs_lookup_variant(struct draw_vertex_shader *vs,
const struct draw_vs_variant_key *key)
{
/* Lookup existing variant:
*/
for (unsigned i = 0; i < vs->nr_variants; i++)
if (draw_vs_variant_key_compare(key, &vs->variant[i]->key) == 0)
return vs->variant[i];
/* Else have to create a new one:
*/
struct draw_vs_variant *variant = vs->create_variant(vs, key);
if (!variant)
return NULL;
/* Add it to our list, could be smarter:
*/
if (vs->nr_variants < ARRAY_SIZE(vs->variant)) {
vs->variant[vs->nr_variants++] = variant;
} else {
vs->last_variant++;
vs->last_variant %= ARRAY_SIZE(vs->variant);
vs->variant[vs->last_variant]->destroy(vs->variant[vs->last_variant]);
vs->variant[vs->last_variant] = variant;
}
return variant;
}
struct translate *
draw_vs_get_fetch(struct draw_context *draw,
struct translate_key *key)
{
if (!draw->vs.fetch ||
translate_key_compare(&draw->vs.fetch->key, key) != 0) {
translate_key_sanitize(key);
draw->vs.fetch = translate_cache_find(draw->vs.fetch_cache, key);
}
return draw->vs.fetch;
}
struct translate *
draw_vs_get_emit(struct draw_context *draw,
struct translate_key *key)
{
if (!draw->vs.emit ||
translate_key_compare(&draw->vs.emit->key, key) != 0) {
translate_key_sanitize(key);
draw->vs.emit = translate_cache_find(draw->vs.emit_cache, key);
}
return draw->vs.emit;
}
void
draw_vs_attach_so(struct draw_vertex_shader *dvs,
const struct pipe_stream_output_info *info)
{
dvs->state.stream_output = *info;
}
void
draw_vs_reset_so(struct draw_vertex_shader *dvs)
{
memset(&dvs->state.stream_output, 0, sizeof(dvs->state.stream_output));
}
+203
View File
@@ -0,0 +1,203 @@
/**************************************************************************
*
* Copyright 2007 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 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 ITS 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.
*
**************************************************************************/
/* Authors: Keith Whitwell <[email protected]>
*/
#ifndef DRAW_VS_H
#define DRAW_VS_H
#include "draw_context.h"
#include "draw_private.h"
#include "draw_vertex.h"
#include "tgsi/tgsi_scan.h"
struct draw_context;
struct pipe_shader_state;
struct draw_variant_input {
enum pipe_format format;
unsigned buffer;
unsigned offset;
unsigned instance_divisor;
};
struct draw_variant_output {
enum attrib_emit format; /* output format */
unsigned vs_output:8; /* which vertex shader output is this? */
unsigned offset:24; /* offset into output vertex */
};
struct draw_variant_element {
struct draw_variant_input in;
struct draw_variant_output out;
};
struct draw_vs_variant_key {
unsigned output_stride;
unsigned nr_elements:8; /* max2(nr_inputs, nr_outputs) */
unsigned nr_inputs:8;
unsigned nr_outputs:8;
unsigned viewport:1;
unsigned clip:1;
unsigned const_vbuffers:5;
struct draw_variant_element element[PIPE_MAX_ATTRIBS];
};
struct draw_vs_variant {
struct draw_vs_variant_key key;
struct draw_vertex_shader *vs;
void (*set_buffer)(struct draw_vs_variant *,
unsigned i,
const void *ptr,
unsigned stride,
unsigned max_stride);
void (UTIL_CDECL *run_linear)(struct draw_vs_variant *shader,
unsigned start,
unsigned count,
void *output_buffer);
void (UTIL_CDECL *run_elts)(struct draw_vs_variant *shader,
const unsigned *elts,
unsigned count,
void *output_buffer);
void (*destroy)(struct draw_vs_variant *);
};
/**
* Private version of the compiled vertex_shader
*/
struct draw_vertex_shader {
struct draw_context *draw;
/* This member will disappear shortly:
*/
struct pipe_shader_state state;
struct tgsi_shader_info info;
unsigned position_output;
unsigned viewport_index_output;
unsigned edgeflag_output;
unsigned clipvertex_output;
unsigned ccdistance_output[PIPE_MAX_CLIP_OR_CULL_DISTANCE_ELEMENT_COUNT];
/* Extracted from shader:
*/
const float (*immediates)[4];
struct draw_vs_variant *variant[16];
unsigned nr_variants;
unsigned last_variant;
struct draw_vs_variant *(*create_variant)(struct draw_vertex_shader *shader,
const struct draw_vs_variant_key *key);
void (*prepare)(struct draw_vertex_shader *shader,
struct draw_context *draw);
/* Run the shader - this interface will get cleaned up in the
* future:
*/
void (*run_linear)(struct draw_vertex_shader *shader,
const float (*input)[4],
float (*output)[4],
const struct draw_buffer_info *constants,
unsigned count,
unsigned input_stride,
unsigned output_stride,
const unsigned *fetch_elts);
void (*delete)(struct draw_vertex_shader *);
};
struct draw_vs_variant *
draw_vs_lookup_variant(struct draw_vertex_shader *base,
const struct draw_vs_variant_key *key);
/********************************************************************************
* Internal functions:
*/
struct draw_vertex_shader *
draw_create_vs_exec(struct draw_context *draw,
const struct pipe_shader_state *templ);
#if DRAW_LLVM_AVAILABLE
struct draw_vertex_shader *
draw_create_vs_llvm(struct draw_context *draw,
const struct pipe_shader_state *state);
#endif
/********************************************************************************
* Helpers for vs implementations that don't do their own fetch/emit variants.
* Means these can be shared between shaders.
*/
struct translate;
struct translate_key;
struct translate *
draw_vs_get_fetch(struct draw_context *draw,
struct translate_key *key);
struct translate *
draw_vs_get_emit(struct draw_context *draw,
struct translate_key *key);
struct draw_vs_variant *
draw_vs_create_variant_generic(struct draw_vertex_shader *vs,
const struct draw_vs_variant_key *key);
static inline int
draw_vs_variant_keysize(const struct draw_vs_variant_key *key)
{
return 2 * sizeof(int) + key->nr_elements * sizeof(struct draw_variant_element);
}
static inline int
draw_vs_variant_key_compare(const struct draw_vs_variant_key *a,
const struct draw_vs_variant_key *b)
{
int keysize = draw_vs_variant_keysize(a);
return memcmp(a, b, keysize);
}
#define MAX_TGSI_VERTICES 4
#endif
+252
View File
@@ -0,0 +1,252 @@
/**************************************************************************
*
* Copyright 2007 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 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 ITS 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.
*
**************************************************************************/
/*
* Authors:
* Keith Whitwell <[email protected]>
* Brian Paul
*/
#include "util/u_math.h"
#include "util/u_memory.h"
#include "util/ralloc.h"
#include "pipe/p_shader_tokens.h"
#include "pipe/p_context.h"
#include "nir/nir_to_tgsi.h"
#include "draw_private.h"
#include "draw_context.h"
#include "draw_vs.h"
#include "tgsi/tgsi_parse.h"
#include "tgsi/tgsi_scan.h"
#include "tgsi/tgsi_exec.h"
struct exec_vertex_shader {
struct draw_vertex_shader base;
struct tgsi_exec_machine *machine;
};
static struct exec_vertex_shader *
exec_vertex_shader(struct draw_vertex_shader *vs)
{
return (struct exec_vertex_shader *)vs;
}
/* Not required for run_linear.
*/
static void
vs_exec_prepare(struct draw_vertex_shader *shader,
struct draw_context *draw)
{
struct exec_vertex_shader *evs = exec_vertex_shader(shader);
assert(!draw->llvm);
/* Specify the vertex program to interpret/execute.
* Avoid rebinding when possible.
*/
if (evs->machine->Tokens != shader->state.tokens) {
tgsi_exec_machine_bind_shader(evs->machine,
shader->state.tokens,
draw->vs.tgsi.sampler,
draw->vs.tgsi.image,
draw->vs.tgsi.buffer);
}
}
/**
* Simplified vertex shader interface for the pt paths. Given the
* complexity of code-generating all the above operations together,
* it's time to try doing all the other stuff separately.
*/
static void
vs_exec_run_linear(struct draw_vertex_shader *shader,
const float (*input)[4],
float (*output)[4],
const struct draw_buffer_info *constants,
unsigned count,
unsigned input_stride,
unsigned output_stride,
const unsigned *fetch_elts)
{
struct exec_vertex_shader *evs = exec_vertex_shader(shader);
struct tgsi_exec_machine *machine = evs->machine;
unsigned int i, j;
unsigned slot;
bool clamp_vertex_color = shader->draw->rasterizer->clamp_vertex_color;
assert(!shader->draw->llvm);
tgsi_exec_set_constant_buffers(machine, PIPE_MAX_CONSTANT_BUFFERS,
(const struct tgsi_exec_consts_info *)constants);
if (shader->info.uses_instanceid) {
unsigned i = machine->SysSemanticToIndex[TGSI_SEMANTIC_INSTANCEID];
assert(i < ARRAY_SIZE(machine->SystemValue));
for (j = 0; j < TGSI_QUAD_SIZE; j++)
machine->SystemValue[i].xyzw[0].i[j] = shader->draw->instance_id;
}
for (i = 0; i < count; i += MAX_TGSI_VERTICES) {
unsigned int max_vertices = MIN2(MAX_TGSI_VERTICES, count - i);
/* Swizzle inputs.
*/
for (j = 0; j < max_vertices; j++) {
#if 0
debug_printf("%d) Input vert:\n", i + j);
for (slot = 0; slot < shader->info.num_inputs; slot++) {
debug_printf("\t%d: %f %f %f %f\n", slot,
input[slot][0],
input[slot][1],
input[slot][2],
input[slot][3]);
}
#endif
int basevertex = shader->draw->pt.user.eltSize ? shader->draw->pt.user.eltBias : shader->draw->start_index;
if (shader->info.uses_vertexid) {
unsigned vid = machine->SysSemanticToIndex[TGSI_SEMANTIC_VERTEXID];
assert(vid < ARRAY_SIZE(machine->SystemValue));
machine->SystemValue[vid].xyzw[0].i[j] = fetch_elts ? fetch_elts[i + j] : (i + j + basevertex);
}
if (shader->info.uses_basevertex) {
unsigned vid = machine->SysSemanticToIndex[TGSI_SEMANTIC_BASEVERTEX];
assert(vid < ARRAY_SIZE(machine->SystemValue));
machine->SystemValue[vid].xyzw[0].i[j] = basevertex;
}
if (shader->info.uses_vertexid_nobase) {
unsigned vid = machine->SysSemanticToIndex[TGSI_SEMANTIC_VERTEXID_NOBASE];
assert(vid < ARRAY_SIZE(machine->SystemValue));
machine->SystemValue[vid].xyzw[0].i[j] = fetch_elts ? (fetch_elts[i + j] - basevertex) : (i + j);
}
for (slot = 0; slot < shader->info.num_inputs; slot++) {
#if 0
assert(!util_is_inf_or_nan(input[slot][0]));
assert(!util_is_inf_or_nan(input[slot][1]));
assert(!util_is_inf_or_nan(input[slot][2]));
assert(!util_is_inf_or_nan(input[slot][3]));
#endif
machine->Inputs[slot].xyzw[0].f[j] = input[slot][0];
machine->Inputs[slot].xyzw[1].f[j] = input[slot][1];
machine->Inputs[slot].xyzw[2].f[j] = input[slot][2];
machine->Inputs[slot].xyzw[3].f[j] = input[slot][3];
}
input = (const float (*)[4])((const char *)input + input_stride);
}
machine->NonHelperMask = (1 << max_vertices) - 1;
/* run interpreter */
tgsi_exec_machine_run(machine, 0);
/* Unswizzle all output results.
*/
for (j = 0; j < max_vertices; j++) {
for (slot = 0; slot < shader->info.num_outputs; slot++) {
enum tgsi_semantic name = shader->info.output_semantic_name[slot];
if (clamp_vertex_color &&
(name == TGSI_SEMANTIC_COLOR || name == TGSI_SEMANTIC_BCOLOR)) {
output[slot][0] = SATURATE(machine->Outputs[slot].xyzw[0].f[j]);
output[slot][1] = SATURATE(machine->Outputs[slot].xyzw[1].f[j]);
output[slot][2] = SATURATE(machine->Outputs[slot].xyzw[2].f[j]);
output[slot][3] = SATURATE(machine->Outputs[slot].xyzw[3].f[j]);
} else {
output[slot][0] = machine->Outputs[slot].xyzw[0].f[j];
output[slot][1] = machine->Outputs[slot].xyzw[1].f[j];
output[slot][2] = machine->Outputs[slot].xyzw[2].f[j];
output[slot][3] = machine->Outputs[slot].xyzw[3].f[j];
}
}
#if 0
debug_printf("%d) Post xform vert:\n", i + j);
for (slot = 0; slot < shader->info.num_outputs; slot++) {
debug_printf("\t%d: %f %f %f %f\n", slot,
output[slot][0],
output[slot][1],
output[slot][2],
output[slot][3]);
assert(!util_is_inf_or_nan(output[slot][0]));
}
#endif
output = (float (*)[4])((char *)output + output_stride);
}
}
}
static void
vs_exec_delete(struct draw_vertex_shader *dvs)
{
FREE((void*) dvs->state.tokens);
FREE(dvs);
}
struct draw_vertex_shader *
draw_create_vs_exec(struct draw_context *draw,
const struct pipe_shader_state *state)
{
struct exec_vertex_shader *vs = CALLOC_STRUCT(exec_vertex_shader);
if (!vs)
return NULL;
if (state->type == PIPE_SHADER_IR_NIR) {
vs->base.state.type = PIPE_SHADER_IR_TGSI;
vs->base.state.tokens = nir_to_tgsi(state->ir.nir, draw->pipe->screen);
} else {
assert(state->type == PIPE_SHADER_IR_TGSI);
vs->base.state.type = state->type;
/* we need to keep a local copy of the tokens */
vs->base.state.tokens = tgsi_dup_tokens(state->tokens);
if (!vs->base.state.tokens) {
FREE(vs);
return NULL;
}
}
tgsi_scan_shader(vs->base.state.tokens, &vs->base.info);
vs->base.state.stream_output = state->stream_output;
vs->base.draw = draw;
vs->base.prepare = vs_exec_prepare;
vs->base.run_linear = vs_exec_run_linear;
vs->base.delete = vs_exec_delete;
vs->base.create_variant = draw_vs_create_variant_generic;
vs->machine = draw->vs.tgsi.machine;
return &vs->base;
}
+129
View File
@@ -0,0 +1,129 @@
/**************************************************************************
*
* Copyright 2010 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 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 ITS 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 "util/u_math.h"
#include "util/u_memory.h"
#include "pipe/p_shader_tokens.h"
#include "pipe/p_screen.h"
#include "draw_private.h"
#include "draw_context.h"
#include "draw_vs.h"
#include "draw_llvm.h"
#include "tgsi/tgsi_parse.h"
#include "tgsi/tgsi_scan.h"
#include "nir/nir_to_tgsi_info.h"
#include "nir.h"
static void
vs_llvm_prepare(struct draw_vertex_shader *shader,
struct draw_context *draw)
{
/*struct llvm_vertex_shader *evs = llvm_vertex_shader(shader);*/
}
static void
vs_llvm_run_linear(struct draw_vertex_shader *shader,
const float (*input)[4],
float (*output)[4],
const struct draw_buffer_info *constants,
unsigned count,
unsigned input_stride,
unsigned output_stride,
const unsigned *elts)
{
/* we should never get here since the entire pipeline is
* generated in draw_pt_fetch_shade_pipeline_llvm.c */
assert(0);
}
static void
vs_llvm_delete(struct draw_vertex_shader *dvs)
{
struct llvm_vertex_shader *shader = llvm_vertex_shader(dvs);
struct draw_llvm_variant_list_item *li, *next;
LIST_FOR_EACH_ENTRY_SAFE(li, next, &shader->variants.list, list) {
draw_llvm_destroy_variant(li->base);
}
assert(shader->variants_cached == 0);
ralloc_free(dvs->state.ir.nir);
FREE((void*) dvs->state.tokens);
FREE(dvs);
}
struct draw_vertex_shader *
draw_create_vs_llvm(struct draw_context *draw,
const struct pipe_shader_state *state)
{
struct llvm_vertex_shader *vs = CALLOC_STRUCT(llvm_vertex_shader);
if (!vs)
return NULL;
if (state->type == PIPE_SHADER_IR_NIR) {
vs->base.state.ir.nir = state->ir.nir;
nir_shader *nir = state->ir.nir;
if (!nir->options->lower_uniforms_to_ubo)
NIR_PASS(_, state->ir.nir, nir_lower_uniforms_to_ubo, false, false);
nir_tgsi_scan_shader(state->ir.nir, &vs->base.info, true);
} else {
/* we make a private copy of the tokens */
vs->base.state.tokens = tgsi_dup_tokens(state->tokens);
if (!vs->base.state.tokens) {
FREE(vs);
return NULL;
}
tgsi_scan_shader(state->tokens, &vs->base.info);
}
vs->variant_key_size =
draw_llvm_variant_key_size(
vs->base.info.file_max[TGSI_FILE_INPUT]+1,
vs->base.info.file_max[TGSI_FILE_SAMPLER]+1,
vs->base.info.file_max[TGSI_FILE_SAMPLER_VIEW]+1,
vs->base.info.file_max[TGSI_FILE_IMAGE]+1);
vs->base.state.type = state->type;
vs->base.state.stream_output = state->stream_output;
vs->base.draw = draw;
vs->base.prepare = vs_llvm_prepare;
vs->base.run_linear = vs_llvm_run_linear;
vs->base.delete = vs_llvm_delete;
vs->base.create_variant = draw_vs_create_variant_generic;
list_inithead(&vs->variants.list);
return &vs->base;
}
@@ -0,0 +1,348 @@
/**************************************************************************
*
* Copyright 2007 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 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 ITS 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.
*
**************************************************************************/
/*
* Authors:
* Keith Whitwell <[email protected]>
*/
#include "util/u_memory.h"
#include "util/u_math.h"
#include "draw/draw_context.h"
#include "draw/draw_private.h"
#include "draw/draw_vbuf.h"
#include "draw/draw_vertex.h"
#include "draw/draw_vs.h"
#include "translate/translate.h"
/* A first pass at incorporating vertex fetch/emit functionality into
*/
struct draw_vs_variant_generic {
struct draw_vs_variant base;
struct draw_vertex_shader *shader;
struct draw_context *draw;
/* Basic plan is to run these two translate functions before/after
* the vertex shader's existing run_linear() routine to simulate
* the inclusion of this functionality into the shader...
*
* Next will look at actually including it.
*/
struct translate *fetch;
struct translate *emit;
unsigned temp_vertex_stride;
};
static void
vsvg_set_buffer(struct draw_vs_variant *variant,
unsigned buffer,
const void *ptr,
unsigned stride,
unsigned max_index)
{
struct draw_vs_variant_generic *vsvg = (struct draw_vs_variant_generic *)variant;
vsvg->fetch->set_buffer(vsvg->fetch, buffer, ptr, stride, max_index);
}
static const struct pipe_viewport_state *
find_viewport(struct draw_context *draw,
char *buffer,
unsigned vertex_idx,
unsigned stride)
{
int viewport_index_output =
draw_current_shader_viewport_index_output(draw);
const char *ptr = buffer + vertex_idx * stride;
const unsigned *data = (const unsigned *) ptr;
int viewport_index =
draw_current_shader_uses_viewport_index(draw) ?
data[viewport_index_output * 4] : 0;
viewport_index = draw_clamp_viewport_idx(viewport_index);
return &draw->viewports[viewport_index];
}
/* Mainly for debug at this stage:
*/
static void
do_rhw_viewport(struct draw_vs_variant_generic *vsvg,
unsigned count,
void *output_buffer)
{
char *ptr = (char *)output_buffer;
unsigned stride = vsvg->temp_vertex_stride;
ptr += vsvg->base.vs->position_output * 4 * sizeof(float);
for (unsigned j = 0; j < count; j++, ptr += stride) {
const struct pipe_viewport_state *viewport =
find_viewport(vsvg->base.vs->draw, (char*)output_buffer,
j, stride);
const float *scale = viewport->scale;
const float *trans = viewport->translate;
float *data = (float *)ptr;
float w = 1.0f / data[3];
data[0] = data[0] * w * scale[0] + trans[0];
data[1] = data[1] * w * scale[1] + trans[1];
data[2] = data[2] * w * scale[2] + trans[2];
data[3] = w;
}
}
static void
do_viewport(struct draw_vs_variant_generic *vsvg,
unsigned count,
void *output_buffer)
{
char *ptr = (char *)output_buffer;
unsigned stride = vsvg->temp_vertex_stride;
ptr += vsvg->base.vs->position_output * 4 * sizeof(float);
for (unsigned j = 0; j < count; j++, ptr += stride) {
const struct pipe_viewport_state *viewport =
find_viewport(vsvg->base.vs->draw, (char*)output_buffer,
j, stride);
const float *scale = viewport->scale;
const float *trans = viewport->translate;
float *data = (float *)ptr;
data[0] = data[0] * scale[0] + trans[0];
data[1] = data[1] * scale[1] + trans[1];
data[2] = data[2] * scale[2] + trans[2];
}
}
static void UTIL_CDECL
vsvg_run_elts(struct draw_vs_variant *variant,
const unsigned *elts,
unsigned count,
void *output_buffer)
{
struct draw_vs_variant_generic *vsvg = (struct draw_vs_variant_generic *)variant;
unsigned temp_vertex_stride = vsvg->temp_vertex_stride;
void *temp_buffer = MALLOC(align(count,4) * temp_vertex_stride +
DRAW_EXTRA_VERTICES_PADDING);
if (0) debug_printf("%s %d \n", __func__, count);
/* Want to do this in small batches for cache locality?
*/
vsvg->fetch->run_elts(vsvg->fetch,
elts,
count,
vsvg->draw->start_instance,
vsvg->draw->instance_id,
temp_buffer);
vsvg->base.vs->run_linear(vsvg->base.vs,
temp_buffer,
temp_buffer,
vsvg->base.vs->draw->pt.user.constants[MESA_SHADER_VERTEX],
count,
temp_vertex_stride,
temp_vertex_stride, NULL);
/* FIXME: geometry shading? */
if (vsvg->base.key.clip) {
/* not really handling clipping, just do the rhw so we can
* see the results...
*/
do_rhw_viewport(vsvg, count, temp_buffer);
} else if (vsvg->base.key.viewport) {
do_viewport(vsvg, count, temp_buffer);
}
vsvg->emit->set_buffer(vsvg->emit,
0,
temp_buffer,
temp_vertex_stride,
~0);
vsvg->emit->set_buffer(vsvg->emit,
1,
&vsvg->draw->rasterizer->point_size,
0,
~0);
vsvg->emit->run(vsvg->emit,
0, count,
vsvg->draw->start_instance,
vsvg->draw->instance_id,
output_buffer);
FREE(temp_buffer);
}
static void UTIL_CDECL
vsvg_run_linear(struct draw_vs_variant *variant,
unsigned start,
unsigned count,
void *output_buffer)
{
struct draw_vs_variant_generic *vsvg = (struct draw_vs_variant_generic *)variant;
unsigned temp_vertex_stride = vsvg->temp_vertex_stride;
void *temp_buffer = MALLOC(align(count,4) * temp_vertex_stride +
DRAW_EXTRA_VERTICES_PADDING);
if (0) debug_printf("%s %d %d (sz %d, %d)\n", __func__, start, count,
vsvg->base.key.output_stride,
temp_vertex_stride);
vsvg->fetch->run(vsvg->fetch,
start,
count,
vsvg->draw->start_instance,
vsvg->draw->instance_id,
temp_buffer);
vsvg->base.vs->run_linear(vsvg->base.vs,
temp_buffer,
temp_buffer,
vsvg->base.vs->draw->pt.user.constants[MESA_SHADER_VERTEX],
count,
temp_vertex_stride,
temp_vertex_stride, NULL);
if (vsvg->base.key.clip) {
/* not really handling clipping, just do the rhw so we can
* see the results...
*/
do_rhw_viewport(vsvg, count, temp_buffer);
} else if (vsvg->base.key.viewport) {
do_viewport(vsvg, count, temp_buffer);
}
vsvg->emit->set_buffer(vsvg->emit,
0,
temp_buffer,
temp_vertex_stride,
~0);
vsvg->emit->set_buffer(vsvg->emit,
1,
&vsvg->draw->rasterizer->point_size,
0,
~0);
vsvg->emit->run(vsvg->emit,
0, count,
vsvg->draw->start_instance,
vsvg->draw->instance_id,
output_buffer);
FREE(temp_buffer);
}
static void
vsvg_destroy(struct draw_vs_variant *variant)
{
FREE(variant);
}
struct draw_vs_variant *
draw_vs_create_variant_generic(struct draw_vertex_shader *vs,
const struct draw_vs_variant_key *key)
{
struct draw_vs_variant_generic *vsvg = CALLOC_STRUCT(draw_vs_variant_generic);
if (!vsvg)
return NULL;
vsvg->base.key = *key;
vsvg->base.vs = vs;
vsvg->base.set_buffer = vsvg_set_buffer;
vsvg->base.run_elts = vsvg_run_elts;
vsvg->base.run_linear = vsvg_run_linear;
vsvg->base.destroy = vsvg_destroy;
vsvg->draw = vs->draw;
vsvg->temp_vertex_stride = MAX2(key->nr_inputs,
draw_total_vs_outputs(vs->draw)) * 4 * sizeof(float);
/* Build free-standing fetch and emit functions:
*/
struct translate_key fetch;
fetch.nr_elements = key->nr_inputs;
fetch.output_stride = vsvg->temp_vertex_stride;
for (unsigned i = 0; i < key->nr_inputs; i++) {
fetch.element[i].type = TRANSLATE_ELEMENT_NORMAL;
fetch.element[i].input_format = key->element[i].in.format;
fetch.element[i].input_buffer = key->element[i].in.buffer;
fetch.element[i].input_offset = key->element[i].in.offset;
fetch.element[i].instance_divisor = 0;
fetch.element[i].output_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
fetch.element[i].output_offset = i * 4 * sizeof(float);
assert(fetch.element[i].output_offset < fetch.output_stride);
}
struct translate_key emit;
emit.nr_elements = key->nr_outputs;
emit.output_stride = key->output_stride;
for (unsigned i = 0; i < key->nr_outputs; i++) {
if (key->element[i].out.format != EMIT_1F_PSIZE) {
emit.element[i].type = TRANSLATE_ELEMENT_NORMAL;
emit.element[i].input_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
emit.element[i].input_buffer = 0;
emit.element[i].input_offset = key->element[i].out.vs_output * 4 * sizeof(float);
emit.element[i].instance_divisor = 0;
emit.element[i].output_format = draw_translate_vinfo_format(key->element[i].out.format);
emit.element[i].output_offset = key->element[i].out.offset;
assert(emit.element[i].input_offset <= fetch.output_stride);
} else {
emit.element[i].type = TRANSLATE_ELEMENT_NORMAL;
emit.element[i].input_format = PIPE_FORMAT_R32_FLOAT;
emit.element[i].input_buffer = 1;
emit.element[i].input_offset = 0;
emit.element[i].instance_divisor = 0;
emit.element[i].output_format = PIPE_FORMAT_R32_FLOAT;
emit.element[i].output_offset = key->element[i].out.offset;
}
}
vsvg->fetch = draw_vs_get_fetch(vs->draw, &fetch);
vsvg->emit = draw_vs_get_emit(vs->draw, &emit);
return &vsvg->base;
}
@@ -0,0 +1,965 @@
/**************************************************************************
*
* Copyright 2015 Advanced Micro Devices, Inc.
* Copyright 2008 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
* THE AUTHOR(S) 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 "dd_pipe.h"
#include "tgsi/tgsi_parse.h"
#include "util/u_inlines.h"
#include "util/u_memory.h"
static void
safe_memcpy(void *dst, const void *src, size_t size)
{
if (src)
memcpy(dst, src, size);
else
memset(dst, 0, size);
}
/********************************************************************
* queries
*/
static struct pipe_query *
dd_context_create_query(struct pipe_context *_pipe, unsigned query_type,
unsigned index)
{
struct pipe_context *pipe = dd_context(_pipe)->pipe;
struct pipe_query *query;
query = pipe->create_query(pipe, query_type, index);
/* Wrap query object. */
if (query) {
struct dd_query *dd_query = CALLOC_STRUCT(dd_query);
if (dd_query) {
dd_query->type = query_type;
dd_query->query = query;
query = (struct pipe_query *)dd_query;
} else {
pipe->destroy_query(pipe, query);
query = NULL;
}
}
return query;
}
static struct pipe_query *
dd_context_create_batch_query(struct pipe_context *_pipe, unsigned num_queries,
unsigned *query_types)
{
struct pipe_context *pipe = dd_context(_pipe)->pipe;
struct pipe_query *query;
query = pipe->create_batch_query(pipe, num_queries, query_types);
/* Wrap query object. */
if (query) {
struct dd_query *dd_query = CALLOC_STRUCT(dd_query);
if (dd_query) {
/* no special handling for batch queries yet */
dd_query->type = query_types[0];
dd_query->query = query;
query = (struct pipe_query *)dd_query;
} else {
pipe->destroy_query(pipe, query);
query = NULL;
}
}
return query;
}
static void
dd_context_destroy_query(struct pipe_context *_pipe,
struct pipe_query *query)
{
struct pipe_context *pipe = dd_context(_pipe)->pipe;
pipe->destroy_query(pipe, dd_query_unwrap(query));
FREE(query);
}
static bool
dd_context_begin_query(struct pipe_context *_pipe, struct pipe_query *query)
{
struct dd_context *dctx = dd_context(_pipe);
struct pipe_context *pipe = dctx->pipe;
return pipe->begin_query(pipe, dd_query_unwrap(query));
}
static bool
dd_context_end_query(struct pipe_context *_pipe, struct pipe_query *query)
{
struct dd_context *dctx = dd_context(_pipe);
struct pipe_context *pipe = dctx->pipe;
return pipe->end_query(pipe, dd_query_unwrap(query));
}
static bool
dd_context_get_query_result(struct pipe_context *_pipe,
struct pipe_query *query, bool wait,
union pipe_query_result *result)
{
struct pipe_context *pipe = dd_context(_pipe)->pipe;
return pipe->get_query_result(pipe, dd_query_unwrap(query), wait, result);
}
static void
dd_context_set_active_query_state(struct pipe_context *_pipe, bool enable)
{
struct pipe_context *pipe = dd_context(_pipe)->pipe;
pipe->set_active_query_state(pipe, enable);
}
static void
dd_context_render_condition(struct pipe_context *_pipe,
struct pipe_query *query, bool condition,
enum pipe_render_cond_flag mode)
{
struct dd_context *dctx = dd_context(_pipe);
struct pipe_context *pipe = dctx->pipe;
struct dd_draw_state *dstate = &dctx->draw_state;
pipe->render_condition(pipe, dd_query_unwrap(query), condition, mode);
dstate->render_cond.query = dd_query(query);
dstate->render_cond.condition = condition;
dstate->render_cond.mode = mode;
}
/********************************************************************
* constant (immutable) non-shader states
*/
#define DD_CSO_CREATE(name, shortname) \
static void * \
dd_context_create_##name##_state(struct pipe_context *_pipe, \
const struct pipe_##name##_state *state) \
{ \
struct pipe_context *pipe = dd_context(_pipe)->pipe; \
struct dd_state *hstate = CALLOC_STRUCT(dd_state); \
\
if (!hstate) \
return NULL; \
hstate->cso = pipe->create_##name##_state(pipe, state); \
hstate->state.shortname = *state; \
return hstate; \
}
#define DD_CSO_BIND(name, shortname) \
static void \
dd_context_bind_##name##_state(struct pipe_context *_pipe, void *state) \
{ \
struct dd_context *dctx = dd_context(_pipe); \
struct pipe_context *pipe = dctx->pipe; \
struct dd_state *hstate = state; \
\
dctx->draw_state.shortname = hstate; \
pipe->bind_##name##_state(pipe, hstate ? hstate->cso : NULL); \
}
#define DD_CSO_DELETE(name) \
static void \
dd_context_delete_##name##_state(struct pipe_context *_pipe, void *state) \
{ \
struct dd_context *dctx = dd_context(_pipe); \
struct pipe_context *pipe = dctx->pipe; \
struct dd_state *hstate = state; \
\
pipe->delete_##name##_state(pipe, hstate->cso); \
FREE(hstate); \
}
#define DD_CSO_WHOLE(name, shortname) \
DD_CSO_CREATE(name, shortname) \
DD_CSO_BIND(name, shortname) \
DD_CSO_DELETE(name)
DD_CSO_WHOLE(blend, blend)
DD_CSO_WHOLE(rasterizer, rs)
DD_CSO_WHOLE(depth_stencil_alpha, dsa)
DD_CSO_CREATE(sampler, sampler)
DD_CSO_DELETE(sampler)
static void
dd_context_bind_sampler_states(struct pipe_context *_pipe,
mesa_shader_stage shader,
unsigned start, unsigned count, void **states)
{
struct dd_context *dctx = dd_context(_pipe);
struct pipe_context *pipe = dctx->pipe;
safe_memcpy(&dctx->draw_state.sampler_states[shader][start], states,
sizeof(void*) * count);
if (states) {
void *samp[PIPE_MAX_SAMPLERS];
int i;
for (i = 0; i < count; i++) {
struct dd_state *s = states[i];
samp[i] = s ? s->cso : NULL;
}
pipe->bind_sampler_states(pipe, shader, start, count, samp);
}
else
pipe->bind_sampler_states(pipe, shader, start, count, NULL);
}
static void *
dd_context_create_vertex_elements_state(struct pipe_context *_pipe,
unsigned num_elems,
const struct pipe_vertex_element *elems)
{
struct pipe_context *pipe = dd_context(_pipe)->pipe;
struct dd_state *hstate = CALLOC_STRUCT(dd_state);
if (!hstate)
return NULL;
hstate->cso = pipe->create_vertex_elements_state(pipe, num_elems, elems);
memcpy(hstate->state.velems.velems, elems, sizeof(elems[0]) * num_elems);
hstate->state.velems.count = num_elems;
return hstate;
}
DD_CSO_BIND(vertex_elements, velems)
DD_CSO_DELETE(vertex_elements)
/********************************************************************
* shaders
*/
#define DD_SHADER_NOCREATE(NAME, name) \
static void \
dd_context_bind_##name##_state(struct pipe_context *_pipe, void *state) \
{ \
struct dd_context *dctx = dd_context(_pipe); \
struct pipe_context *pipe = dctx->pipe; \
struct dd_state *hstate = state; \
\
dctx->draw_state.shaders[MESA_SHADER_##NAME] = hstate; \
pipe->bind_##name##_state(pipe, hstate ? hstate->cso : NULL); \
} \
\
static void \
dd_context_delete_##name##_state(struct pipe_context *_pipe, void *state) \
{ \
struct dd_context *dctx = dd_context(_pipe); \
struct pipe_context *pipe = dctx->pipe; \
struct dd_state *hstate = state; \
\
pipe->delete_##name##_state(pipe, hstate->cso); \
if (hstate->state.shader.type == PIPE_SHADER_IR_TGSI) \
tgsi_free_tokens(hstate->state.shader.tokens); \
FREE(hstate); \
}
#define DD_SHADER(NAME, name) \
static void * \
dd_context_create_##name##_state(struct pipe_context *_pipe, \
const struct pipe_shader_state *state) \
{ \
struct pipe_context *pipe = dd_context(_pipe)->pipe; \
struct dd_state *hstate = CALLOC_STRUCT(dd_state); \
\
if (!hstate) \
return NULL; \
hstate->cso = pipe->create_##name##_state(pipe, state); \
hstate->state.shader = *state; \
if (hstate->state.shader.type == PIPE_SHADER_IR_TGSI) \
hstate->state.shader.tokens = tgsi_dup_tokens(state->tokens); \
return hstate; \
} \
\
DD_SHADER_NOCREATE(NAME, name)
DD_SHADER(FRAGMENT, fs)
DD_SHADER(VERTEX, vs)
DD_SHADER(GEOMETRY, gs)
DD_SHADER(TESS_CTRL, tcs)
DD_SHADER(TESS_EVAL, tes)
DD_SHADER(TASK, ts)
DD_SHADER(MESH, ms)
static void * \
dd_context_create_compute_state(struct pipe_context *_pipe,
const struct pipe_compute_state *state)
{
struct pipe_context *pipe = dd_context(_pipe)->pipe;
struct dd_state *hstate = CALLOC_STRUCT(dd_state);
if (!hstate)
return NULL;
hstate->cso = pipe->create_compute_state(pipe, state);
hstate->state.shader.type = state->ir_type;
if (state->ir_type == PIPE_SHADER_IR_TGSI)
hstate->state.shader.tokens = tgsi_dup_tokens(state->prog);
return hstate;
}
DD_SHADER_NOCREATE(COMPUTE, compute)
/********************************************************************
* immediate states
*/
#define DD_IMM_STATE(name, type, deref, ref) \
static void \
dd_context_set_##name(struct pipe_context *_pipe, type deref) \
{ \
struct dd_context *dctx = dd_context(_pipe); \
struct pipe_context *pipe = dctx->pipe; \
\
dctx->draw_state.name = deref; \
pipe->set_##name(pipe, ref); \
}
DD_IMM_STATE(blend_color, const struct pipe_blend_color, *state, state)
DD_IMM_STATE(stencil_ref, const struct pipe_stencil_ref, state, state)
DD_IMM_STATE(clip_state, const struct pipe_clip_state, *state, state)
DD_IMM_STATE(sample_mask, unsigned, sample_mask, sample_mask)
DD_IMM_STATE(min_samples, unsigned, min_samples, min_samples)
DD_IMM_STATE(framebuffer_state, const struct pipe_framebuffer_state, *state, state)
DD_IMM_STATE(polygon_stipple, const struct pipe_poly_stipple, *state, state)
static void
dd_context_set_constant_buffer(struct pipe_context *_pipe,
mesa_shader_stage shader, uint index,
const struct pipe_constant_buffer *constant_buffer)
{
struct dd_context *dctx = dd_context(_pipe);
struct pipe_context *pipe = dctx->pipe;
safe_memcpy(&dctx->draw_state.constant_buffers[shader][index],
constant_buffer, sizeof(*constant_buffer));
pipe->set_constant_buffer(pipe, shader, index, constant_buffer);
}
static void
dd_context_set_scissor_states(struct pipe_context *_pipe,
unsigned start_slot, unsigned num_scissors,
const struct pipe_scissor_state *states)
{
struct dd_context *dctx = dd_context(_pipe);
struct pipe_context *pipe = dctx->pipe;
safe_memcpy(&dctx->draw_state.scissors[start_slot], states,
sizeof(*states) * num_scissors);
pipe->set_scissor_states(pipe, start_slot, num_scissors, states);
}
static void
dd_context_set_viewport_states(struct pipe_context *_pipe,
unsigned start_slot, unsigned num_viewports,
const struct pipe_viewport_state *states)
{
struct dd_context *dctx = dd_context(_pipe);
struct pipe_context *pipe = dctx->pipe;
safe_memcpy(&dctx->draw_state.viewports[start_slot], states,
sizeof(*states) * num_viewports);
pipe->set_viewport_states(pipe, start_slot, num_viewports, states);
}
static void dd_context_set_tess_state(struct pipe_context *_pipe,
const float default_outer_level[4],
const float default_inner_level[2])
{
struct dd_context *dctx = dd_context(_pipe);
struct pipe_context *pipe = dctx->pipe;
memcpy(dctx->draw_state.tess_default_levels, default_outer_level,
sizeof(float) * 4);
memcpy(dctx->draw_state.tess_default_levels+4, default_inner_level,
sizeof(float) * 2);
pipe->set_tess_state(pipe, default_outer_level, default_inner_level);
}
static void dd_context_set_patch_vertices(struct pipe_context *_pipe,
uint8_t patch_vertices)
{
struct dd_context *dctx = dd_context(_pipe);
struct pipe_context *pipe = dctx->pipe;
pipe->set_patch_vertices(pipe, patch_vertices);
}
static void dd_context_set_window_rectangles(struct pipe_context *_pipe,
bool include,
unsigned num_rectangles,
const struct pipe_scissor_state *rects)
{
struct dd_context *dctx = dd_context(_pipe);
struct pipe_context *pipe = dctx->pipe;
pipe->set_window_rectangles(pipe, include, num_rectangles, rects);
}
/********************************************************************
* views
*/
static struct pipe_sampler_view *
dd_context_create_sampler_view(struct pipe_context *_pipe,
struct pipe_resource *resource,
const struct pipe_sampler_view *templ)
{
struct pipe_context *pipe = dd_context(_pipe)->pipe;
struct pipe_sampler_view *view =
pipe->create_sampler_view(pipe, resource, templ);
if (!view)
return NULL;
view->context = _pipe;
return view;
}
static void
dd_context_sampler_view_destroy(struct pipe_context *_pipe,
struct pipe_sampler_view *view)
{
struct pipe_context *pipe = dd_context(_pipe)->pipe;
pipe->sampler_view_destroy(pipe, view);
}
static void
dd_context_sampler_view_release(struct pipe_context *_pipe,
struct pipe_sampler_view *view)
{
struct pipe_context *pipe = dd_context(_pipe)->pipe;
pipe->sampler_view_release(pipe, view);
}
static struct pipe_stream_output_target *
dd_context_create_stream_output_target(struct pipe_context *_pipe,
struct pipe_resource *res,
unsigned buffer_offset,
unsigned buffer_size)
{
struct pipe_context *pipe = dd_context(_pipe)->pipe;
struct pipe_stream_output_target *view =
pipe->create_stream_output_target(pipe, res, buffer_offset,
buffer_size);
if (!view)
return NULL;
view->context = _pipe;
return view;
}
static void
dd_context_stream_output_target_destroy(struct pipe_context *_pipe,
struct pipe_stream_output_target *target)
{
struct pipe_context *pipe = dd_context(_pipe)->pipe;
pipe->stream_output_target_destroy(pipe, target);
}
/********************************************************************
* set states
*/
static void
dd_context_set_sampler_views(struct pipe_context *_pipe,
mesa_shader_stage shader,
unsigned start, unsigned num,
unsigned unbind_num_trailing_slots,
struct pipe_sampler_view **views)
{
struct dd_context *dctx = dd_context(_pipe);
struct pipe_context *pipe = dctx->pipe;
safe_memcpy(&dctx->draw_state.sampler_views[shader][start], views,
sizeof(views[0]) * num);
safe_memcpy(&dctx->draw_state.sampler_views[shader][start + num], NULL,
sizeof(views[0]) * unbind_num_trailing_slots);
pipe->set_sampler_views(pipe, shader, start, num,
unbind_num_trailing_slots, views);
}
static void
dd_context_set_shader_images(struct pipe_context *_pipe,
mesa_shader_stage shader,
unsigned start, unsigned num,
unsigned unbind_num_trailing_slots,
const struct pipe_image_view *views)
{
struct dd_context *dctx = dd_context(_pipe);
struct pipe_context *pipe = dctx->pipe;
safe_memcpy(&dctx->draw_state.shader_images[shader][start], views,
sizeof(views[0]) * num);
safe_memcpy(&dctx->draw_state.shader_images[shader][start + num], NULL,
sizeof(views[0]) * unbind_num_trailing_slots);
pipe->set_shader_images(pipe, shader, start, num,
unbind_num_trailing_slots, views);
}
static void
dd_context_set_shader_buffers(struct pipe_context *_pipe,
mesa_shader_stage shader,
unsigned start, unsigned num_buffers,
const struct pipe_shader_buffer *buffers,
unsigned writable_bitmask)
{
struct dd_context *dctx = dd_context(_pipe);
struct pipe_context *pipe = dctx->pipe;
safe_memcpy(&dctx->draw_state.shader_buffers[shader][start], buffers,
sizeof(buffers[0]) * num_buffers);
pipe->set_shader_buffers(pipe, shader, start, num_buffers, buffers,
writable_bitmask);
}
static void
dd_context_set_vertex_buffers(struct pipe_context *_pipe,
unsigned num_buffers,
const struct pipe_vertex_buffer *buffers)
{
struct dd_context *dctx = dd_context(_pipe);
struct pipe_context *pipe = dctx->pipe;
safe_memcpy(&dctx->draw_state.vertex_buffers[0], buffers,
sizeof(buffers[0]) * num_buffers);
if (dctx->num_vertex_buffers > num_buffers) {
safe_memcpy(&dctx->draw_state.vertex_buffers[num_buffers], NULL,
sizeof(buffers[0]) * (dctx->num_vertex_buffers - num_buffers));
}
pipe->set_vertex_buffers(pipe, num_buffers, buffers);
dctx->num_vertex_buffers = num_buffers;
}
static void
dd_context_set_stream_output_targets(struct pipe_context *_pipe,
unsigned num_targets,
struct pipe_stream_output_target **tgs,
const unsigned *offsets,
enum mesa_prim output_prim)
{
struct dd_context *dctx = dd_context(_pipe);
struct pipe_context *pipe = dctx->pipe;
struct dd_draw_state *dstate = &dctx->draw_state;
dstate->num_so_targets = num_targets;
safe_memcpy(dstate->so_targets, tgs, sizeof(*tgs) * num_targets);
safe_memcpy(dstate->so_offsets, offsets, sizeof(*offsets) * num_targets);
pipe->set_stream_output_targets(pipe, num_targets, tgs, offsets, output_prim);
}
static void
dd_context_fence_server_sync(struct pipe_context *_pipe,
struct pipe_fence_handle *fence,
uint64_t value)
{
struct dd_context *dctx = dd_context(_pipe);
struct pipe_context *pipe = dctx->pipe;
pipe->fence_server_sync(pipe, fence, value);
}
static void
dd_context_create_fence_fd(struct pipe_context *_pipe,
struct pipe_fence_handle **fence,
int fd,
enum pipe_fd_type type)
{
struct dd_context *dctx = dd_context(_pipe);
struct pipe_context *pipe = dctx->pipe;
pipe->create_fence_fd(pipe, fence, fd, type);
}
void
dd_thread_join(struct dd_context *dctx)
{
mtx_lock(&dctx->mutex);
dctx->kill_thread = true;
cnd_signal(&dctx->cond);
mtx_unlock(&dctx->mutex);
thrd_join(dctx->thread, NULL);
}
static void
dd_context_destroy(struct pipe_context *_pipe)
{
struct dd_context *dctx = dd_context(_pipe);
struct pipe_context *pipe = dctx->pipe;
dd_thread_join(dctx);
mtx_destroy(&dctx->mutex);
cnd_destroy(&dctx->cond);
assert(list_is_empty(&dctx->records));
if (pipe->set_log_context) {
pipe->set_log_context(pipe, NULL);
if (dd_screen(dctx->base.screen)->dump_mode == DD_DUMP_ALL_CALLS) {
FILE *f = dd_get_file_stream(dd_screen(dctx->base.screen), 0);
if (f) {
fprintf(f, "Remainder of driver log:\n\n");
}
u_log_new_page_print(&dctx->log, f);
fclose(f);
}
}
u_log_context_destroy(&dctx->log);
pipe->destroy(pipe);
FREE(dctx);
}
/********************************************************************
* miscellaneous
*/
static void
dd_context_texture_barrier(struct pipe_context *_pipe, unsigned flags)
{
struct pipe_context *pipe = dd_context(_pipe)->pipe;
pipe->texture_barrier(pipe, flags);
}
static void
dd_context_memory_barrier(struct pipe_context *_pipe, unsigned flags)
{
struct pipe_context *pipe = dd_context(_pipe)->pipe;
pipe->memory_barrier(pipe, flags);
}
static bool
dd_context_resource_commit(struct pipe_context *_pipe,
struct pipe_resource *resource,
unsigned level, struct pipe_box *box, bool commit)
{
struct pipe_context *pipe = dd_context(_pipe)->pipe;
return pipe->resource_commit(pipe, resource, level, box, commit);
}
static void
dd_context_set_global_binding(struct pipe_context *_pipe,
unsigned first, unsigned count,
struct pipe_resource **resources,
uint32_t **handles)
{
struct pipe_context *pipe = dd_context(_pipe)->pipe;
pipe->set_global_binding(pipe, first, count, resources, handles);
}
static void
dd_context_get_sample_position(struct pipe_context *_pipe,
unsigned sample_count, unsigned sample_index,
float *out_value)
{
struct pipe_context *pipe = dd_context(_pipe)->pipe;
pipe->get_sample_position(pipe, sample_count, sample_index,
out_value);
}
static void
dd_context_invalidate_resource(struct pipe_context *_pipe,
struct pipe_resource *resource)
{
struct pipe_context *pipe = dd_context(_pipe)->pipe;
pipe->invalidate_resource(pipe, resource);
}
static enum pipe_reset_status
dd_context_get_device_reset_status(struct pipe_context *_pipe)
{
struct pipe_context *pipe = dd_context(_pipe)->pipe;
return pipe->get_device_reset_status(pipe);
}
static void
dd_context_set_device_reset_callback(struct pipe_context *_pipe,
const struct pipe_device_reset_callback *cb)
{
struct pipe_context *pipe = dd_context(_pipe)->pipe;
pipe->set_device_reset_callback(pipe, cb);
}
static void
dd_context_emit_string_marker(struct pipe_context *_pipe,
const char *string, int len)
{
struct dd_context *dctx = dd_context(_pipe);
struct pipe_context *pipe = dctx->pipe;
pipe->emit_string_marker(pipe, string, len);
dd_parse_apitrace_marker(string, len, &dctx->draw_state.apitrace_call_number);
}
static void
dd_context_dump_debug_state(struct pipe_context *_pipe, FILE *stream,
unsigned flags)
{
struct pipe_context *pipe = dd_context(_pipe)->pipe;
pipe->dump_debug_state(pipe, stream, flags);
}
static uint64_t
dd_context_create_texture_handle(struct pipe_context *_pipe,
struct pipe_sampler_view *view,
const struct pipe_sampler_state *state)
{
struct pipe_context *pipe = dd_context(_pipe)->pipe;
return pipe->create_texture_handle(pipe, view, state);
}
static void
dd_context_delete_texture_handle(struct pipe_context *_pipe, uint64_t handle)
{
struct pipe_context *pipe = dd_context(_pipe)->pipe;
pipe->delete_texture_handle(pipe, handle);
}
static void
dd_context_make_texture_handle_resident(struct pipe_context *_pipe,
uint64_t handle, bool resident)
{
struct pipe_context *pipe = dd_context(_pipe)->pipe;
pipe->make_texture_handle_resident(pipe, handle, resident);
}
static uint64_t
dd_context_create_image_handle(struct pipe_context *_pipe,
const struct pipe_image_view *image)
{
struct pipe_context *pipe = dd_context(_pipe)->pipe;
return pipe->create_image_handle(pipe, image);
}
static void
dd_context_delete_image_handle(struct pipe_context *_pipe, uint64_t handle)
{
struct pipe_context *pipe = dd_context(_pipe)->pipe;
pipe->delete_image_handle(pipe, handle);
}
static void
dd_context_make_image_handle_resident(struct pipe_context *_pipe,
uint64_t handle, unsigned access,
bool resident)
{
struct pipe_context *pipe = dd_context(_pipe)->pipe;
pipe->make_image_handle_resident(pipe, handle, access, resident);
}
static void
dd_context_set_context_param(struct pipe_context *_pipe,
enum pipe_context_param param,
unsigned value)
{
struct pipe_context *pipe = dd_context(_pipe)->pipe;
pipe->set_context_param(pipe, param, value);
}
static void
dd_context_set_inlinable_constants(struct pipe_context *_pipe,
mesa_shader_stage shader,
uint num_values, uint32_t *values)
{
struct pipe_context *pipe = dd_context(_pipe)->pipe;
pipe->set_inlinable_constants(pipe, shader, num_values, values);
}
struct pipe_context *
dd_context_create(struct dd_screen *dscreen, struct pipe_context *pipe)
{
struct dd_context *dctx;
if (!pipe)
return NULL;
dctx = CALLOC_STRUCT(dd_context);
if (!dctx)
goto fail;
dctx->pipe = pipe;
dctx->base.priv = pipe->priv; /* expose wrapped priv data */
dctx->base.screen = &dscreen->base;
dctx->base.stream_uploader = pipe->stream_uploader;
dctx->base.const_uploader = pipe->const_uploader;
dctx->base.destroy = dd_context_destroy;
CTX_INIT(render_condition);
CTX_INIT(create_query);
CTX_INIT(create_batch_query);
CTX_INIT(destroy_query);
CTX_INIT(begin_query);
CTX_INIT(end_query);
CTX_INIT(get_query_result);
CTX_INIT(set_active_query_state);
CTX_INIT(create_blend_state);
CTX_INIT(bind_blend_state);
CTX_INIT(delete_blend_state);
CTX_INIT(create_sampler_state);
CTX_INIT(bind_sampler_states);
CTX_INIT(delete_sampler_state);
CTX_INIT(create_rasterizer_state);
CTX_INIT(bind_rasterizer_state);
CTX_INIT(delete_rasterizer_state);
CTX_INIT(create_depth_stencil_alpha_state);
CTX_INIT(bind_depth_stencil_alpha_state);
CTX_INIT(delete_depth_stencil_alpha_state);
CTX_INIT(create_fs_state);
CTX_INIT(bind_fs_state);
CTX_INIT(delete_fs_state);
CTX_INIT(create_vs_state);
CTX_INIT(bind_vs_state);
CTX_INIT(delete_vs_state);
CTX_INIT(create_gs_state);
CTX_INIT(bind_gs_state);
CTX_INIT(delete_gs_state);
CTX_INIT(create_tcs_state);
CTX_INIT(bind_tcs_state);
CTX_INIT(delete_tcs_state);
CTX_INIT(create_tes_state);
CTX_INIT(bind_tes_state);
CTX_INIT(delete_tes_state);
CTX_INIT(create_compute_state);
CTX_INIT(bind_compute_state);
CTX_INIT(delete_compute_state);
CTX_INIT(create_ts_state);
CTX_INIT(bind_ts_state);
CTX_INIT(delete_ts_state);
CTX_INIT(create_ms_state);
CTX_INIT(bind_ms_state);
CTX_INIT(delete_ms_state);
CTX_INIT(create_vertex_elements_state);
CTX_INIT(bind_vertex_elements_state);
CTX_INIT(delete_vertex_elements_state);
CTX_INIT(set_blend_color);
CTX_INIT(set_stencil_ref);
CTX_INIT(set_sample_mask);
CTX_INIT(set_min_samples);
CTX_INIT(set_clip_state);
CTX_INIT(set_constant_buffer);
CTX_INIT(set_framebuffer_state);
CTX_INIT(set_polygon_stipple);
CTX_INIT(set_scissor_states);
CTX_INIT(set_viewport_states);
CTX_INIT(set_sampler_views);
CTX_INIT(set_tess_state);
CTX_INIT(set_patch_vertices);
CTX_INIT(set_shader_buffers);
CTX_INIT(set_shader_images);
CTX_INIT(set_vertex_buffers);
CTX_INIT(set_window_rectangles);
CTX_INIT(create_stream_output_target);
CTX_INIT(stream_output_target_destroy);
CTX_INIT(set_stream_output_targets);
CTX_INIT(create_fence_fd);
CTX_INIT(fence_server_sync);
CTX_INIT(create_sampler_view);
CTX_INIT(sampler_view_destroy);
CTX_INIT(sampler_view_release);
CTX_INIT(texture_barrier);
CTX_INIT(memory_barrier);
CTX_INIT(resource_commit);
CTX_INIT(set_global_binding);
/* create_video_codec */
/* create_video_buffer */
CTX_INIT(get_sample_position);
CTX_INIT(invalidate_resource);
CTX_INIT(get_device_reset_status);
CTX_INIT(set_device_reset_callback);
CTX_INIT(dump_debug_state);
CTX_INIT(emit_string_marker);
CTX_INIT(create_texture_handle);
CTX_INIT(delete_texture_handle);
CTX_INIT(make_texture_handle_resident);
CTX_INIT(create_image_handle);
CTX_INIT(delete_image_handle);
CTX_INIT(make_image_handle_resident);
CTX_INIT(set_context_param);
CTX_INIT(set_inlinable_constants);
dd_init_draw_functions(dctx);
u_log_context_init(&dctx->log);
if (pipe->set_log_context)
pipe->set_log_context(pipe, &dctx->log);
dctx->draw_state.sample_mask = ~0;
list_inithead(&dctx->records);
(void) mtx_init(&dctx->mutex, mtx_plain);
(void) cnd_init(&dctx->cond);
if (thrd_success != u_thread_create(&dctx->thread,dd_thread_main, dctx)) {
mtx_destroy(&dctx->mutex);
goto fail;
}
return &dctx->base;
fail:
FREE(dctx);
pipe->destroy(pipe);
return NULL;
}
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,392 @@
/**************************************************************************
*
* Copyright 2015 Advanced Micro Devices, Inc.
* Copyright 2008 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
* THE AUTHOR(S) 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 DD_H_
#define DD_H_
#include "pipe/p_context.h"
#include "pipe/p_state.h"
#include "pipe/p_screen.h"
#include "dd_util.h"
#include "util/u_thread.h"
#include "util/list.h"
#include "util/u_log.h"
#include "util/u_queue.h"
struct dd_context;
enum dd_dump_mode {
DD_DUMP_ONLY_HANGS,
DD_DUMP_ALL_CALLS,
DD_DUMP_APITRACE_CALL,
};
struct dd_screen
{
struct pipe_screen base;
struct pipe_screen *screen;
unsigned timeout_ms;
enum dd_dump_mode dump_mode;
bool flush_always;
bool transfers;
bool verbose;
unsigned skip_count;
unsigned apitrace_dump_call;
};
enum call_type
{
CALL_FLUSH,
CALL_DRAW_VBO,
CALL_LAUNCH_GRID,
CALL_RESOURCE_COPY_REGION,
CALL_IMAGE_COPY_BUFFER,
CALL_BLIT,
CALL_FLUSH_RESOURCE,
CALL_CLEAR,
CALL_CLEAR_BUFFER,
CALL_CLEAR_TEXTURE,
CALL_CLEAR_RENDER_TARGET,
CALL_CLEAR_DEPTH_STENCIL,
CALL_GENERATE_MIPMAP,
CALL_GET_QUERY_RESULT_RESOURCE,
CALL_TRANSFER_MAP,
CALL_TRANSFER_FLUSH_REGION,
CALL_TRANSFER_UNMAP,
CALL_BUFFER_SUBDATA,
CALL_TEXTURE_SUBDATA,
CALL_DRAW_MESH_TASKS,
};
struct call_resource_copy_region
{
struct pipe_resource *dst;
unsigned dst_level;
unsigned dstx, dsty, dstz;
struct pipe_resource *src;
unsigned src_level;
struct pipe_box src_box;
};
struct call_image_copy_buffer
{
struct pipe_resource *dst;
struct pipe_resource *src;
unsigned buffer_offset;
unsigned buffer_stride;
unsigned buffer_layer_stride;
unsigned level;
struct pipe_box box;
};
struct call_clear
{
unsigned buffers;
uint32_t color_clear_mask;
uint8_t stencil_clear_mask;
struct pipe_scissor_state scissor_state;
union pipe_color_union color;
double depth;
unsigned stencil;
};
struct call_clear_buffer
{
struct pipe_resource *res;
unsigned offset;
unsigned size;
const void *clear_value;
int clear_value_size;
};
struct call_generate_mipmap {
struct pipe_resource *res;
enum pipe_format format;
unsigned base_level;
unsigned last_level;
unsigned first_layer;
unsigned last_layer;
};
struct call_flush {
unsigned flags;
};
struct call_draw_info {
struct pipe_draw_info info;
unsigned drawid_offset;
struct pipe_draw_indirect_info indirect;
struct pipe_draw_start_count_bias draw;
};
struct call_get_query_result_resource {
struct pipe_query *query;
enum pipe_query_type query_type;
enum pipe_query_flags flags;
enum pipe_query_value_type result_type;
int index;
struct pipe_resource *resource;
unsigned offset;
};
struct call_transfer_map {
struct pipe_transfer *transfer_ptr;
struct pipe_transfer transfer;
void *ptr;
};
struct call_transfer_flush_region {
struct pipe_transfer *transfer_ptr;
struct pipe_transfer transfer;
struct pipe_box box;
};
struct call_transfer_unmap {
struct pipe_transfer *transfer_ptr;
struct pipe_transfer transfer;
};
struct call_buffer_subdata {
struct pipe_resource *resource;
unsigned usage;
unsigned offset;
unsigned size;
const void *data;
};
struct call_texture_subdata {
struct pipe_resource *resource;
unsigned level;
unsigned usage;
struct pipe_box box;
const void *data;
unsigned stride;
uintptr_t layer_stride;
};
struct dd_call
{
enum call_type type;
union {
struct call_flush flush;
struct call_draw_info draw_vbo;
struct pipe_grid_info launch_grid;
struct call_resource_copy_region resource_copy_region;
struct call_image_copy_buffer image_copy_buffer;
struct pipe_blit_info blit;
struct pipe_resource *flush_resource;
struct call_clear clear;
struct call_clear_buffer clear_buffer;
struct call_generate_mipmap generate_mipmap;
struct call_get_query_result_resource get_query_result_resource;
struct call_transfer_map transfer_map;
struct call_transfer_flush_region transfer_flush_region;
struct call_transfer_unmap transfer_unmap;
struct call_buffer_subdata buffer_subdata;
struct call_texture_subdata texture_subdata;
} info;
};
struct dd_query
{
unsigned type;
struct pipe_query *query;
};
struct dd_state
{
void *cso;
union {
struct pipe_blend_state blend;
struct pipe_depth_stencil_alpha_state dsa;
struct pipe_rasterizer_state rs;
struct pipe_sampler_state sampler;
struct {
struct pipe_vertex_element velems[PIPE_MAX_ATTRIBS];
unsigned count;
} velems;
struct pipe_shader_state shader;
} state;
};
struct dd_draw_state
{
struct {
struct dd_query *query;
bool condition;
unsigned mode;
} render_cond;
struct pipe_vertex_buffer vertex_buffers[PIPE_MAX_ATTRIBS];
unsigned num_so_targets;
struct pipe_stream_output_target *so_targets[PIPE_MAX_SO_BUFFERS];
unsigned so_offsets[PIPE_MAX_SO_BUFFERS];
struct dd_state *shaders[MESA_SHADER_MESH_STAGES];
struct pipe_constant_buffer constant_buffers[MESA_SHADER_MESH_STAGES][PIPE_MAX_CONSTANT_BUFFERS];
struct pipe_sampler_view *sampler_views[MESA_SHADER_MESH_STAGES][PIPE_MAX_SAMPLERS];
struct dd_state *sampler_states[MESA_SHADER_MESH_STAGES][PIPE_MAX_SAMPLERS];
struct pipe_image_view shader_images[MESA_SHADER_MESH_STAGES][PIPE_MAX_SHADER_IMAGES];
struct pipe_shader_buffer shader_buffers[MESA_SHADER_MESH_STAGES][PIPE_MAX_SHADER_BUFFERS];
struct dd_state *velems;
struct dd_state *rs;
struct dd_state *dsa;
struct dd_state *blend;
struct pipe_blend_color blend_color;
struct pipe_stencil_ref stencil_ref;
unsigned sample_mask;
unsigned min_samples;
struct pipe_clip_state clip_state;
struct pipe_framebuffer_state framebuffer_state;
struct pipe_poly_stipple polygon_stipple;
struct pipe_scissor_state scissors[PIPE_MAX_VIEWPORTS];
struct pipe_viewport_state viewports[PIPE_MAX_VIEWPORTS];
float tess_default_levels[6];
unsigned apitrace_call_number;
};
struct dd_draw_state_copy
{
struct dd_draw_state base;
/* dd_draw_state_copy does not reference real CSOs. Instead, it points to
* these variables, which serve as storage.
*/
struct dd_query render_cond;
struct dd_state shaders[MESA_SHADER_MESH_STAGES];
struct dd_state sampler_states[MESA_SHADER_MESH_STAGES][PIPE_MAX_SAMPLERS];
struct dd_state velems;
struct dd_state rs;
struct dd_state dsa;
struct dd_state blend;
};
struct dd_draw_record {
struct list_head list;
struct dd_context *dctx;
int64_t time_before;
int64_t time_after;
unsigned draw_call;
/* The fence pointers are guaranteed to be valid once driver_finished is signalled */
struct pipe_fence_handle *prev_bottom_of_pipe;
struct pipe_fence_handle *top_of_pipe;
struct pipe_fence_handle *bottom_of_pipe;
struct dd_call call;
struct dd_draw_state_copy draw_state;
struct util_queue_fence driver_finished;
struct u_log_page *log_page;
};
struct dd_context
{
struct pipe_context base;
struct pipe_context *pipe;
struct dd_draw_state draw_state;
unsigned num_draw_calls;
unsigned num_vertex_buffers;
struct u_log_context log;
/* Pipelined hang detection.
*
* Before each draw call, a new dd_draw_record is created that contains
* a copy of all states. After each draw call, the driver's log is added
* to this record. Additionally, deferred fences are associated to each
* record both before and after the draw.
*
* The records are handed off to a separate thread which waits on the
* records' fences. Records with signalled fences are freed. When a timeout
* is detected, the thread dumps the records of in-flight draws.
*/
thrd_t thread;
mtx_t mutex;
cnd_t cond;
struct list_head records; /* oldest record first */
unsigned num_records;
bool kill_thread;
bool api_stalled;
};
struct pipe_context *
dd_context_create(struct dd_screen *dscreen, struct pipe_context *pipe);
void
dd_init_draw_functions(struct dd_context *dctx);
void
dd_thread_join(struct dd_context *dctx);
int
dd_thread_main(void *input);
FILE *
dd_get_file_stream(struct dd_screen *dscreen, unsigned apitrace_call_number);
static inline struct dd_context *
dd_context(struct pipe_context *pipe)
{
return (struct dd_context *)pipe;
}
static inline struct dd_screen *
dd_screen(struct pipe_screen *screen)
{
return (struct dd_screen*)screen;
}
static inline struct dd_query *
dd_query(struct pipe_query *query)
{
return (struct dd_query *)query;
}
static inline struct pipe_query *
dd_query_unwrap(struct pipe_query *query)
{
if (query) {
return dd_query(query)->query;
} else {
return NULL;
}
}
#define CTX_INIT(_member) \
dctx->base._member = dctx->pipe->_member ? dd_context_##_member : NULL
#endif /* DD_H_ */
@@ -0,0 +1,44 @@
/**************************************************************************
*
* Copyright 2015 Advanced Micro Devices, Inc.
* Copyright 2010 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
* THE AUTHOR(S) 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 DD_PUBLIC_H_
#define DD_PUBLIC_H_
struct pipe_screen;
#ifdef __cplusplus
extern "C" {
#endif
PUBLIC struct pipe_screen *
ddebug_screen_create(struct pipe_screen *screen);
#ifdef __cplusplus
}
#endif
#endif /* DD_PUBLIC_H_ */
@@ -0,0 +1,706 @@
/**************************************************************************
*
* Copyright 2015 Advanced Micro Devices, Inc.
* Copyright 2008 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
* THE AUTHOR(S) 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 "dd_pipe.h"
#include "dd_public.h"
#include "util/u_memory.h"
#include <ctype.h>
#include <stdio.h>
static const char *
dd_screen_get_name(struct pipe_screen *_screen)
{
struct pipe_screen *screen = dd_screen(_screen)->screen;
return screen->get_name(screen);
}
static const char *
dd_screen_get_vendor(struct pipe_screen *_screen)
{
struct pipe_screen *screen = dd_screen(_screen)->screen;
return screen->get_vendor(screen);
}
static const char *
dd_screen_get_device_vendor(struct pipe_screen *_screen)
{
struct pipe_screen *screen = dd_screen(_screen)->screen;
return screen->get_device_vendor(screen);
}
static struct disk_cache *
dd_screen_get_disk_shader_cache(struct pipe_screen *_screen)
{
struct pipe_screen *screen = dd_screen(_screen)->screen;
return screen->get_disk_shader_cache(screen);
}
static uint64_t
dd_screen_get_timestamp(struct pipe_screen *_screen)
{
struct pipe_screen *screen = dd_screen(_screen)->screen;
return screen->get_timestamp(screen);
}
static void dd_screen_query_memory_info(struct pipe_screen *_screen,
struct pipe_memory_info *info)
{
struct pipe_screen *screen = dd_screen(_screen)->screen;
screen->query_memory_info(screen, info);
}
static struct pipe_context *
dd_screen_context_create(struct pipe_screen *_screen, void *priv,
unsigned flags)
{
struct dd_screen *dscreen = dd_screen(_screen);
struct pipe_screen *screen = dscreen->screen;
flags |= PIPE_CONTEXT_DEBUG;
return dd_context_create(dscreen,
screen->context_create(screen, priv, flags));
}
static bool
dd_screen_is_format_supported(struct pipe_screen *_screen,
enum pipe_format format,
enum pipe_texture_target target,
unsigned sample_count,
unsigned storage_sample_count,
unsigned tex_usage)
{
struct pipe_screen *screen = dd_screen(_screen)->screen;
return screen->is_format_supported(screen, format, target, sample_count,
storage_sample_count, tex_usage);
}
static bool
dd_screen_can_create_resource(struct pipe_screen *_screen,
const struct pipe_resource *templat)
{
struct pipe_screen *screen = dd_screen(_screen)->screen;
return screen->can_create_resource(screen, templat);
}
static void
dd_screen_flush_frontbuffer(struct pipe_screen *_screen,
struct pipe_context *_pipe,
struct pipe_resource *resource,
unsigned level, unsigned layer,
void *context_private,
unsigned nboxes,
struct pipe_box *sub_box)
{
struct pipe_screen *screen = dd_screen(_screen)->screen;
struct pipe_context *pipe = _pipe ? dd_context(_pipe)->pipe : NULL;
screen->flush_frontbuffer(screen, pipe, resource, level, layer, context_private,
nboxes, sub_box);
}
static int
dd_screen_get_driver_query_info(struct pipe_screen *_screen,
unsigned index,
struct pipe_driver_query_info *info)
{
struct pipe_screen *screen = dd_screen(_screen)->screen;
return screen->get_driver_query_info(screen, index, info);
}
static int
dd_screen_get_driver_query_group_info(struct pipe_screen *_screen,
unsigned index,
struct pipe_driver_query_group_info *info)
{
struct pipe_screen *screen = dd_screen(_screen)->screen;
return screen->get_driver_query_group_info(screen, index, info);
}
static void
dd_screen_get_driver_uuid(struct pipe_screen *_screen, char *uuid)
{
struct pipe_screen *screen = dd_screen(_screen)->screen;
screen->get_driver_uuid(screen, uuid);
}
static void
dd_screen_get_device_uuid(struct pipe_screen *_screen, char *uuid)
{
struct pipe_screen *screen = dd_screen(_screen)->screen;
screen->get_device_uuid(screen, uuid);
}
/********************************************************************
* resource
*/
static struct pipe_resource *
dd_screen_resource_create(struct pipe_screen *_screen,
const struct pipe_resource *templat)
{
struct pipe_screen *screen = dd_screen(_screen)->screen;
struct pipe_resource *res = screen->resource_create(screen, templat);
if (!res)
return NULL;
res->screen = _screen;
return res;
}
static struct pipe_resource *
dd_screen_resource_from_handle(struct pipe_screen *_screen,
const struct pipe_resource *templ,
struct winsys_handle *handle,
unsigned usage)
{
struct pipe_screen *screen = dd_screen(_screen)->screen;
struct pipe_resource *res =
screen->resource_from_handle(screen, templ, handle, usage);
if (!res)
return NULL;
res->screen = _screen;
return res;
}
static struct pipe_resource *
dd_screen_resource_create_with_modifiers(struct pipe_screen *_screen,
const struct pipe_resource *templat,
const uint64_t *modifiers, int count)
{
struct pipe_screen *screen = dd_screen(_screen)->screen;
struct pipe_resource *res =
screen->resource_create_with_modifiers(screen, templat,
modifiers, count);
if (!res)
return NULL;
res->screen = _screen;
return res;
}
static void
dd_screen_query_dmabuf_modifiers(struct pipe_screen *_screen,
enum pipe_format format, int max,
uint64_t *modifiers,
unsigned int *external_only, int *count)
{
struct pipe_screen *screen = dd_screen(_screen)->screen;
screen->query_dmabuf_modifiers(screen, format, max, modifiers,
external_only, count);
}
static struct pipe_resource *
dd_screen_resource_from_user_memory(struct pipe_screen *_screen,
const struct pipe_resource *templ,
void *user_memory)
{
struct pipe_screen *screen = dd_screen(_screen)->screen;
struct pipe_resource *res =
screen->resource_from_user_memory(screen, templ, user_memory);
if (!res)
return NULL;
res->screen = _screen;
return res;
}
static struct pipe_resource *
dd_screen_resource_from_memobj(struct pipe_screen *_screen,
const struct pipe_resource *templ,
struct pipe_memory_object *memobj,
uint64_t offset)
{
struct pipe_screen *screen = dd_screen(_screen)->screen;
struct pipe_resource *res =
screen->resource_from_memobj(screen, templ, memobj, offset);
if (!res)
return NULL;
res->screen = _screen;
return res;
}
static void
dd_screen_resource_changed(struct pipe_screen *_screen,
struct pipe_resource *res)
{
struct pipe_screen *screen = dd_screen(_screen)->screen;
if (screen->resource_changed)
screen->resource_changed(screen, res);
}
static void
dd_screen_resource_destroy(struct pipe_screen *_screen,
struct pipe_resource *res)
{
struct pipe_screen *screen = dd_screen(_screen)->screen;
screen->resource_destroy(screen, res);
}
static bool
dd_screen_resource_get_handle(struct pipe_screen *_screen,
struct pipe_context *_pipe,
struct pipe_resource *resource,
struct winsys_handle *handle,
unsigned usage)
{
struct pipe_screen *screen = dd_screen(_screen)->screen;
struct pipe_context *pipe = _pipe ? dd_context(_pipe)->pipe : NULL;
return screen->resource_get_handle(screen, pipe, resource, handle, usage);
}
static bool
dd_screen_resource_get_param(struct pipe_screen *_screen,
struct pipe_context *_pipe,
struct pipe_resource *resource,
unsigned plane,
unsigned layer,
unsigned level,
enum pipe_resource_param param,
unsigned handle_usage,
uint64_t *value)
{
struct pipe_screen *screen = dd_screen(_screen)->screen;
struct pipe_context *pipe = _pipe ? dd_context(_pipe)->pipe : NULL;
return screen->resource_get_param(screen, pipe, resource, plane, layer,
level, param, handle_usage, value);
}
static bool
dd_screen_check_resource_capability(struct pipe_screen *_screen,
struct pipe_resource *resource,
unsigned bind)
{
struct pipe_screen *screen = dd_screen(_screen)->screen;
return screen->check_resource_capability(screen, resource, bind);
}
static int
dd_screen_get_sparse_texture_virtual_page_size(struct pipe_screen *_screen,
enum pipe_texture_target target,
bool multi_sample,
enum pipe_format format,
unsigned offset, unsigned size,
int *x, int *y, int *z)
{
struct pipe_screen *screen = dd_screen(_screen)->screen;
return screen->get_sparse_texture_virtual_page_size(
_screen, target, multi_sample, format, offset, size, x, y, z);
}
static bool
dd_screen_is_dmabuf_modifier_supported(struct pipe_screen *_screen,
uint64_t modifier,
enum pipe_format format,
bool *external_only)
{
struct pipe_screen *screen = dd_screen(_screen)->screen;
return screen->is_dmabuf_modifier_supported(screen, modifier, format, external_only);
}
static unsigned int
dd_screen_get_dmabuf_modifier_planes(struct pipe_screen *_screen,
uint64_t modifier,
enum pipe_format format)
{
struct pipe_screen *screen = dd_screen(_screen)->screen;
return screen->get_dmabuf_modifier_planes(screen, modifier, format);
}
/********************************************************************
* fence
*/
static void
dd_screen_fence_reference(struct pipe_screen *_screen,
struct pipe_fence_handle **pdst,
struct pipe_fence_handle *src)
{
struct pipe_screen *screen = dd_screen(_screen)->screen;
screen->fence_reference(screen, pdst, src);
}
static bool
dd_screen_fence_finish(struct pipe_screen *_screen,
struct pipe_context *_ctx,
struct pipe_fence_handle *fence,
uint64_t timeout)
{
struct pipe_screen *screen = dd_screen(_screen)->screen;
struct pipe_context *ctx = _ctx ? dd_context(_ctx)->pipe : NULL;
return screen->fence_finish(screen, ctx, fence, timeout);
}
static int
dd_screen_fence_get_fd(struct pipe_screen *_screen,
struct pipe_fence_handle *fence)
{
struct pipe_screen *screen = dd_screen(_screen)->screen;
return screen->fence_get_fd(screen, fence);
}
/********************************************************************
* vertex state
*/
static struct pipe_vertex_state *
dd_screen_create_vertex_state(struct pipe_screen *_screen,
struct pipe_vertex_buffer *buffer,
const struct pipe_vertex_element *elements,
unsigned num_elements,
struct pipe_resource *indexbuf,
uint32_t full_velem_mask)
{
struct pipe_screen *screen = dd_screen(_screen)->screen;
struct pipe_vertex_state *state =
screen->create_vertex_state(screen, buffer, elements, num_elements,
indexbuf, full_velem_mask);
if (!state)
return NULL;
state->screen = _screen;
return state;
}
static void
dd_screen_vertex_state_destroy(struct pipe_screen *_screen,
struct pipe_vertex_state *state)
{
struct pipe_screen *screen = dd_screen(_screen)->screen;
screen->vertex_state_destroy(screen, state);
}
/********************************************************************
* memobj
*/
static struct pipe_memory_object *
dd_screen_memobj_create_from_handle(struct pipe_screen *_screen,
struct winsys_handle *handle,
bool dedicated)
{
struct pipe_screen *screen = dd_screen(_screen)->screen;
return screen->memobj_create_from_handle(screen, handle, dedicated);
}
static void
dd_screen_memobj_destroy(struct pipe_screen *_screen,
struct pipe_memory_object *memobj)
{
struct pipe_screen *screen = dd_screen(_screen)->screen;
screen->memobj_destroy(screen, memobj);
}
static struct pipe_fence_handle *
dd_screen_semaphore_create(struct pipe_screen *_screen)
{
struct pipe_screen *screen = dd_screen(_screen)->screen;
return screen->semaphore_create(screen);
}
/********************************************************************
* screen
*/
static void
dd_screen_finalize_nir(struct pipe_screen *_screen, struct nir_shader *nir,
bool optimize)
{
struct pipe_screen *screen = dd_screen(_screen)->screen;
screen->finalize_nir(screen, nir, optimize);
}
static void
dd_screen_destroy(struct pipe_screen *_screen)
{
struct dd_screen *dscreen = dd_screen(_screen);
struct pipe_screen *screen = dscreen->screen;
screen->destroy(screen);
FREE(dscreen);
}
static void
skip_space(const char **p)
{
while (isspace(**p))
(*p)++;
}
static bool
match_word(const char **cur, const char *word)
{
size_t len = strlen(word);
if (strncmp(*cur, word, len) != 0)
return false;
const char *p = *cur + len;
if (*p) {
if (!isspace(*p))
return false;
*cur = p + 1;
} else {
*cur = p;
}
return true;
}
static bool
match_uint(const char **cur, unsigned *value)
{
char *end;
unsigned v = strtoul(*cur, &end, 0);
if (end == *cur || (*end && !isspace(*end)))
return false;
*cur = end;
*value = v;
return true;
}
static struct pipe_screen * dd_get_driver_pipe_screen(struct pipe_screen *_screen)
{
struct pipe_screen * screen = dd_screen(_screen)->screen;
if (screen->get_driver_pipe_screen)
return screen->get_driver_pipe_screen(screen);
return screen;
}
struct pipe_screen *
ddebug_screen_create(struct pipe_screen *screen)
{
struct dd_screen *dscreen;
const char *option;
bool flush = false;
bool verbose = false;
bool transfers = false;
unsigned timeout = 1000;
unsigned apitrace_dump_call = 0;
enum dd_dump_mode mode = DD_DUMP_ONLY_HANGS;
option = debug_get_option("GALLIUM_DDEBUG", NULL);
if (!option)
return screen;
if (!strcmp(option, "help")) {
puts("Gallium driver debugger");
puts("");
puts("Usage:");
puts("");
puts(" GALLIUM_DDEBUG=\"[<timeout in ms>] [(always|apitrace <call#)] [flush] [transfers] [verbose]\"");
puts(" GALLIUM_DDEBUG_SKIP=[count]");
puts("");
puts("Dump context and driver information of draw calls into");
puts("$HOME/"DD_DIR"/. By default, watch for GPU hangs and only dump information");
puts("about draw calls related to the hang.");
puts("");
puts("<timeout in ms>");
puts(" Change the default timeout for GPU hang detection (default=1000ms).");
puts(" Setting this to 0 will disable GPU hang detection entirely.");
puts("");
puts("always");
puts(" Dump information about all draw calls.");
puts("");
puts("transfers");
puts(" Also dump and do hang detection on transfers.");
puts("");
puts("apitrace <call#>");
puts(" Dump information about the draw call corresponding to the given");
puts(" apitrace call number and exit.");
puts("");
puts("flush");
puts(" Flush after every draw call.");
puts("");
puts("verbose");
puts(" Write additional information to stderr.");
puts("");
puts("GALLIUM_DDEBUG_SKIP=count");
puts(" Skip dumping on the first count draw calls (only relevant with 'always').");
puts("");
exit(0);
}
for (;;) {
skip_space(&option);
if (!*option)
break;
if (match_word(&option, "always")) {
if (mode == DD_DUMP_APITRACE_CALL) {
printf("ddebug: both 'always' and 'apitrace' specified\n");
exit(1);
}
mode = DD_DUMP_ALL_CALLS;
} else if (match_word(&option, "flush")) {
flush = true;
} else if (match_word(&option, "transfers")) {
transfers = true;
} else if (match_word(&option, "verbose")) {
verbose = true;
} else if (match_word(&option, "apitrace")) {
if (mode != DD_DUMP_ONLY_HANGS) {
printf("ddebug: 'apitrace' can only appear once and not mixed with 'always'\n");
exit(1);
}
if (!match_uint(&option, &apitrace_dump_call)) {
printf("ddebug: expected call number after 'apitrace'\n");
exit(1);
}
mode = DD_DUMP_APITRACE_CALL;
} else if (match_uint(&option, &timeout)) {
/* no-op */
} else {
printf("ddebug: bad options: %s\n", option);
exit(1);
}
}
dscreen = CALLOC_STRUCT(dd_screen);
if (!dscreen)
return NULL;
#define SCR_INIT(_member) \
dscreen->base._member = screen->_member ? dd_screen_##_member : NULL
dscreen->base.destroy = dd_screen_destroy;
dscreen->base.get_name = dd_screen_get_name;
dscreen->base.get_vendor = dd_screen_get_vendor;
dscreen->base.get_device_vendor = dd_screen_get_device_vendor;
SCR_INIT(get_disk_shader_cache);
dscreen->base.query_memory_info = dd_screen_query_memory_info;
/* get_video_param */
/* get_compute_param */
SCR_INIT(get_timestamp);
dscreen->base.context_create = dd_screen_context_create;
dscreen->base.is_format_supported = dd_screen_is_format_supported;
/* is_video_format_supported */
SCR_INIT(can_create_resource);
dscreen->base.resource_create = dd_screen_resource_create;
dscreen->base.resource_create_with_modifiers = dd_screen_resource_create_with_modifiers;
dscreen->base.query_dmabuf_modifiers = dd_screen_query_dmabuf_modifiers;
dscreen->base.resource_from_handle = dd_screen_resource_from_handle;
SCR_INIT(resource_from_memobj);
SCR_INIT(resource_from_user_memory);
SCR_INIT(check_resource_capability);
dscreen->base.resource_get_handle = dd_screen_resource_get_handle;
SCR_INIT(resource_get_param);
SCR_INIT(resource_changed);
dscreen->base.resource_destroy = dd_screen_resource_destroy;
SCR_INIT(flush_frontbuffer);
SCR_INIT(fence_reference);
SCR_INIT(fence_finish);
SCR_INIT(fence_get_fd);
SCR_INIT(memobj_create_from_handle);
SCR_INIT(memobj_destroy);
SCR_INIT(get_driver_query_info);
SCR_INIT(get_driver_query_group_info);
SCR_INIT(get_driver_uuid);
SCR_INIT(get_device_uuid);
SCR_INIT(finalize_nir);
SCR_INIT(get_sparse_texture_virtual_page_size);
SCR_INIT(create_vertex_state);
SCR_INIT(vertex_state_destroy);
dscreen->base.get_driver_pipe_screen = dd_get_driver_pipe_screen;
SCR_INIT(is_dmabuf_modifier_supported);
SCR_INIT(get_dmabuf_modifier_planes);
SCR_INIT(semaphore_create);
/* copy all caps */
*(struct pipe_caps *)&dscreen->base.caps = screen->caps;
*(struct pipe_compute_caps *)&dscreen->base.compute_caps = screen->compute_caps;
memcpy((void *)dscreen->base.shader_caps, screen->shader_caps, sizeof(screen->shader_caps));
memcpy((void *)dscreen->base.nir_options, screen->nir_options, sizeof(screen->nir_options));
#undef SCR_INIT
dscreen->screen = screen;
dscreen->timeout_ms = timeout;
dscreen->dump_mode = mode;
dscreen->flush_always = flush;
dscreen->transfers = transfers;
dscreen->verbose = verbose;
dscreen->apitrace_dump_call = apitrace_dump_call;
switch (dscreen->dump_mode) {
case DD_DUMP_ALL_CALLS:
fprintf(stderr, "Gallium debugger active. Logging all calls.\n");
break;
case DD_DUMP_APITRACE_CALL:
fprintf(stderr, "Gallium debugger active. Going to dump an apitrace call.\n");
break;
default:
fprintf(stderr, "Gallium debugger active.\n");
break;
}
if (dscreen->timeout_ms > 0)
fprintf(stderr, "Hang detection timeout is %ums.\n", dscreen->timeout_ms);
else
fprintf(stderr, "Hang detection is disabled.\n");
dscreen->skip_count = debug_get_num_option("GALLIUM_DDEBUG_SKIP", 0);
if (dscreen->skip_count > 0) {
fprintf(stderr, "Gallium debugger skipping the first %u draw calls.\n",
dscreen->skip_count);
}
return &dscreen->base;
}
@@ -0,0 +1,50 @@
/**************************************************************************
*
* Copyright 2015 Advanced Micro Devices, Inc.
* Copyright 2008 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
* THE AUTHOR(S) 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 DD_UTIL_H
#define DD_UTIL_H
#include <stdio.h>
struct pipe_screen;
/* name of the directory in home */
#define DD_DIR "ddebug_dumps"
void
dd_get_debug_filename_and_mkdir(char *buf, size_t buflen, bool verbose);
FILE *
dd_get_debug_file(bool verbose);
void
dd_parse_apitrace_marker(const char *string, int len, unsigned *call_number);
void
dd_write_header(FILE *f, struct pipe_screen *screen, unsigned apitrace_call_number);
#endif /* DD_UTIL_H */
@@ -0,0 +1,834 @@
/*
* Copyright 2010 Red Hat Inc.
*
* 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
* THE AUTHOR(S) 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 <stdio.h>
#include <errno.h>
#include "pipe/p_defines.h"
#include "pipe/p_state.h"
#include "pipe/p_context.h"
#include "pipe/p_screen.h"
#include "util/u_memory.h"
#include "util/u_inlines.h"
#include "util/format/u_format.h"
#include "util/u_helpers.h"
#include "util/u_upload_mgr.h"
#include "util/u_threaded_context.h"
#include "noop_public.h"
DEBUG_GET_ONCE_BOOL_OPTION(noop, "GALLIUM_NOOP", false)
void noop_init_state_functions(struct pipe_context *ctx);
struct noop_pipe_screen {
struct pipe_screen pscreen;
struct pipe_screen *oscreen;
struct slab_parent_pool pool_transfers;
};
/*
* query
*/
struct noop_query {
struct threaded_query b;
unsigned query;
};
static struct pipe_query *noop_create_query(struct pipe_context *ctx, unsigned query_type, unsigned index)
{
struct noop_query *query = CALLOC_STRUCT(noop_query);
return (struct pipe_query *)query;
}
static void noop_destroy_query(struct pipe_context *ctx, struct pipe_query *query)
{
FREE(query);
}
static bool noop_begin_query(struct pipe_context *ctx, struct pipe_query *query)
{
return true;
}
static bool noop_end_query(struct pipe_context *ctx, struct pipe_query *query)
{
return true;
}
static bool noop_get_query_result(struct pipe_context *ctx,
struct pipe_query *query,
bool wait,
union pipe_query_result *vresult)
{
uint64_t *result = (uint64_t*)vresult;
*result = 0;
return true;
}
static void
noop_set_active_query_state(struct pipe_context *pipe, bool enable)
{
}
/*
* resource
*/
struct noop_resource {
struct threaded_resource b;
unsigned size;
char *data;
struct sw_displaytarget *dt;
};
static struct pipe_resource *noop_resource_create(struct pipe_screen *screen,
const struct pipe_resource *templ)
{
struct noop_resource *nresource;
unsigned stride;
nresource = CALLOC_STRUCT(noop_resource);
if (!nresource)
return NULL;
stride = util_format_get_stride(templ->format, templ->width0);
nresource->b.b = *templ;
nresource->b.b.screen = screen;
nresource->size = stride * templ->height0 * templ->depth0;
nresource->data = MALLOC(nresource->size);
pipe_reference_init(&nresource->b.b.reference, 1);
if (nresource->data == NULL) {
FREE(nresource);
return NULL;
}
threaded_resource_init(&nresource->b.b, false);
return &nresource->b.b;
}
static struct pipe_resource *
noop_resource_create_with_modifiers(struct pipe_screen *screen,
const struct pipe_resource *templ,
const uint64_t *modifiers, int count)
{
struct noop_pipe_screen *noop_screen = (struct noop_pipe_screen*)screen;
struct pipe_screen *oscreen = noop_screen->oscreen;
struct pipe_resource *result;
struct pipe_resource *noop_resource;
result = oscreen->resource_create_with_modifiers(oscreen, templ,
modifiers, count);
noop_resource = noop_resource_create(screen, result);
pipe_resource_reference(&result, NULL);
return noop_resource;
}
static struct pipe_resource *noop_resource_from_handle(struct pipe_screen *screen,
const struct pipe_resource *templ,
struct winsys_handle *handle,
unsigned usage)
{
struct noop_pipe_screen *noop_screen = (struct noop_pipe_screen*)screen;
struct pipe_screen *oscreen = noop_screen->oscreen;
struct pipe_resource *result;
struct pipe_resource *noop_resource;
result = oscreen->resource_from_handle(oscreen, templ, handle, usage);
noop_resource = noop_resource_create(screen, result);
pipe_resource_reference(&result, NULL);
return noop_resource;
}
static bool noop_resource_get_handle(struct pipe_screen *pscreen,
struct pipe_context *ctx,
struct pipe_resource *resource,
struct winsys_handle *handle,
unsigned usage)
{
struct noop_pipe_screen *noop_screen = (struct noop_pipe_screen*)pscreen;
struct pipe_screen *screen = noop_screen->oscreen;
struct pipe_resource *tex;
bool result;
/* resource_get_handle musn't fail. Just create something and return it. */
tex = screen->resource_create(screen, resource);
if (!tex)
return false;
result = screen->resource_get_handle(screen, NULL, tex, handle, usage);
pipe_resource_reference(&tex, NULL);
return result;
}
static bool noop_resource_get_param(struct pipe_screen *pscreen,
struct pipe_context *ctx,
struct pipe_resource *resource,
unsigned plane,
unsigned layer,
unsigned level,
enum pipe_resource_param param,
unsigned handle_usage,
uint64_t *value)
{
struct noop_pipe_screen *noop_screen = (struct noop_pipe_screen*)pscreen;
struct pipe_screen *screen = noop_screen->oscreen;
struct pipe_resource *tex;
bool result;
/* resource_get_param mustn't fail. Just create something and return it. */
tex = screen->resource_create(screen, resource);
if (!tex)
return false;
result = screen->resource_get_param(screen, NULL, tex, 0, 0, 0, param,
handle_usage, value);
pipe_resource_reference(&tex, NULL);
return result;
}
static void noop_resource_destroy(struct pipe_screen *screen,
struct pipe_resource *resource)
{
struct noop_resource *nresource = (struct noop_resource *)resource;
threaded_resource_deinit(resource);
FREE(nresource->data);
FREE(resource);
}
/*
* transfer
*/
static void *noop_transfer_map(struct pipe_context *pipe,
struct pipe_resource *resource,
unsigned level,
unsigned usage,
const struct pipe_box *box,
struct pipe_transfer **ptransfer)
{
struct pipe_transfer *transfer;
struct noop_resource *nresource = (struct noop_resource *)resource;
transfer = (struct pipe_transfer*)CALLOC_STRUCT(threaded_transfer);
if (!transfer)
return NULL;
pipe_resource_reference(&transfer->resource, resource);
transfer->level = level;
transfer->usage = usage;
transfer->box = *box;
transfer->stride = 1;
transfer->layer_stride = 1;
*ptransfer = transfer;
return nresource->data;
}
static void noop_transfer_flush_region(struct pipe_context *pipe,
struct pipe_transfer *transfer,
const struct pipe_box *box)
{
}
static void noop_transfer_unmap(struct pipe_context *pipe,
struct pipe_transfer *transfer)
{
pipe_resource_reference(&transfer->resource, NULL);
FREE(transfer);
}
static void noop_buffer_subdata(struct pipe_context *pipe,
struct pipe_resource *resource,
unsigned usage, unsigned offset,
unsigned size, const void *data)
{
}
static void noop_texture_subdata(struct pipe_context *pipe,
struct pipe_resource *resource,
unsigned level,
unsigned usage,
const struct pipe_box *box,
const void *data,
unsigned stride,
uintptr_t layer_stride)
{
}
/*
* clear/copy
*/
static void noop_clear(struct pipe_context *ctx, unsigned buffers,
uint32_t color_clear_mask, uint8_t stencil_clear_mask,
const struct pipe_scissor_state *scissor_state,
const union pipe_color_union *color, double depth, unsigned stencil)
{
}
static void noop_clear_render_target(struct pipe_context *ctx,
struct pipe_surface *dst,
const union pipe_color_union *color,
unsigned dstx, unsigned dsty,
unsigned width, unsigned height,
bool render_condition_enabled)
{
}
static void noop_clear_depth_stencil(struct pipe_context *ctx,
struct pipe_surface *dst,
unsigned clear_flags,
double depth,
unsigned stencil,
unsigned dstx, unsigned dsty,
unsigned width, unsigned height,
bool render_condition_enabled)
{
}
static void noop_resource_copy_region(struct pipe_context *ctx,
struct pipe_resource *dst,
unsigned dst_level,
unsigned dstx, unsigned dsty, unsigned dstz,
struct pipe_resource *src,
unsigned src_level,
const struct pipe_box *src_box)
{
}
static void noop_image_copy_buffer(struct pipe_context *pipe,
struct pipe_resource *dst,
struct pipe_resource *src,
unsigned buffer_offset,
unsigned buffer_stride,
unsigned buffer_layer_stride,
unsigned level,
const struct pipe_box *box)
{
}
static void noop_blit(struct pipe_context *ctx,
const struct pipe_blit_info *info)
{
}
static void
noop_flush_resource(struct pipe_context *ctx,
struct pipe_resource *resource)
{
}
/*
* context
*/
static void noop_flush(struct pipe_context *ctx,
struct pipe_fence_handle **fence,
unsigned flags)
{
if (fence) {
struct pipe_reference *f = MALLOC_STRUCT(pipe_reference);
f->count = 1;
ctx->screen->fence_reference(ctx->screen, fence, NULL);
*fence = (struct pipe_fence_handle*)f;
}
}
static void noop_destroy_context(struct pipe_context *ctx)
{
if (ctx->stream_uploader)
u_upload_destroy(ctx->stream_uploader);
p_atomic_dec(&ctx->screen->num_contexts);
FREE(ctx);
}
static bool noop_generate_mipmap(struct pipe_context *ctx,
struct pipe_resource *resource,
enum pipe_format format,
unsigned base_level,
unsigned last_level,
unsigned first_layer,
unsigned last_layer)
{
return true;
}
static void noop_invalidate_resource(struct pipe_context *ctx,
struct pipe_resource *resource)
{
}
static void noop_set_context_param(struct pipe_context *ctx,
enum pipe_context_param param,
unsigned value)
{
}
static void noop_set_frontend_noop(struct pipe_context *ctx, bool enable)
{
}
static void noop_replace_buffer_storage(struct pipe_context *ctx,
struct pipe_resource *dst,
struct pipe_resource *src,
unsigned num_rebinds,
uint32_t rebind_mask,
uint32_t delete_buffer_id)
{
}
static struct pipe_fence_handle *
noop_create_fence(struct pipe_context *ctx,
struct tc_unflushed_batch_token *tc_token)
{
struct pipe_reference *f = MALLOC_STRUCT(pipe_reference);
f->count = 1;
return (struct pipe_fence_handle*)f;
}
static bool noop_is_resource_busy(struct pipe_screen *screen,
struct pipe_resource *resource,
unsigned usage)
{
return false;
}
static void
noop_resource_release(struct pipe_context *ctx, struct pipe_resource *resource)
{
pipe_resource_reference(&resource, NULL);
}
static struct pipe_context *noop_create_context(struct pipe_screen *screen,
void *priv, unsigned flags)
{
struct pipe_context *ctx = CALLOC_STRUCT(pipe_context);
if (!ctx)
return NULL;
ctx->screen = screen;
ctx->priv = priv;
ctx->stream_uploader = u_upload_create_default(ctx);
if (!ctx->stream_uploader) {
FREE(ctx);
return NULL;
}
ctx->const_uploader = ctx->stream_uploader;
ctx->destroy = noop_destroy_context;
ctx->flush = noop_flush;
ctx->clear = noop_clear;
ctx->clear_render_target = noop_clear_render_target;
ctx->clear_depth_stencil = noop_clear_depth_stencil;
ctx->resource_copy_region = noop_resource_copy_region;
ctx->image_copy_buffer = noop_image_copy_buffer;
ctx->generate_mipmap = noop_generate_mipmap;
ctx->blit = noop_blit;
ctx->flush_resource = noop_flush_resource;
ctx->create_query = noop_create_query;
ctx->destroy_query = noop_destroy_query;
ctx->begin_query = noop_begin_query;
ctx->end_query = noop_end_query;
ctx->get_query_result = noop_get_query_result;
ctx->set_active_query_state = noop_set_active_query_state;
ctx->buffer_map = noop_transfer_map;
ctx->texture_map = noop_transfer_map;
ctx->transfer_flush_region = noop_transfer_flush_region;
ctx->buffer_unmap = noop_transfer_unmap;
ctx->texture_unmap = noop_transfer_unmap;
ctx->buffer_subdata = noop_buffer_subdata;
ctx->texture_subdata = noop_texture_subdata;
ctx->invalidate_resource = noop_invalidate_resource;
ctx->set_context_param = noop_set_context_param;
ctx->set_frontend_noop = noop_set_frontend_noop;
ctx->resource_release = noop_resource_release;
noop_init_state_functions(ctx);
p_atomic_inc(&screen->num_contexts);
if (!(flags & PIPE_CONTEXT_PREFER_THREADED))
return ctx;
struct pipe_context *tc =
threaded_context_create(ctx,
&((struct noop_pipe_screen*)screen)->pool_transfers,
noop_replace_buffer_storage,
&(struct threaded_context_options) {
.create_fence = noop_create_fence,
.is_resource_busy = noop_is_resource_busy,
},
NULL);
if (tc && tc != ctx)
threaded_context_init_bytes_mapped_limit((struct threaded_context *)tc, 4);
return tc;
}
/*
* pipe_screen
*/
static void noop_flush_frontbuffer(struct pipe_screen *_screen,
struct pipe_context *ctx,
struct pipe_resource *resource,
unsigned level, unsigned layer,
void *context_private, unsigned nboxes, struct pipe_box *box)
{
}
static const char *noop_get_vendor(struct pipe_screen* pscreen)
{
return "X.Org";
}
static const char *noop_get_device_vendor(struct pipe_screen* pscreen)
{
return "NONE";
}
static const char *noop_get_name(struct pipe_screen* pscreen)
{
return "NOOP";
}
static bool noop_is_format_supported(struct pipe_screen* pscreen,
enum pipe_format format,
enum pipe_texture_target target,
unsigned sample_count,
unsigned storage_sample_count,
unsigned usage)
{
struct pipe_screen *screen = ((struct noop_pipe_screen*)pscreen)->oscreen;
return screen->is_format_supported(screen, format, target, sample_count,
storage_sample_count, usage);
}
static uint64_t noop_get_timestamp(struct pipe_screen *pscreen)
{
return 0;
}
static void noop_destroy_screen(struct pipe_screen *screen)
{
struct noop_pipe_screen *noop_screen = (struct noop_pipe_screen*)screen;
struct pipe_screen *oscreen = noop_screen->oscreen;
oscreen->destroy(oscreen);
slab_destroy_parent(&noop_screen->pool_transfers);
FREE(screen);
}
static void noop_fence_reference(struct pipe_screen *screen,
struct pipe_fence_handle **ptr,
struct pipe_fence_handle *fence)
{
if (pipe_reference((struct pipe_reference*)*ptr,
(struct pipe_reference*)fence))
FREE(*ptr);
*ptr = fence;
}
static bool noop_fence_finish(struct pipe_screen *screen,
struct pipe_context *ctx,
struct pipe_fence_handle *fence,
uint64_t timeout)
{
return true;
}
static void noop_query_memory_info(struct pipe_screen *pscreen,
struct pipe_memory_info *info)
{
struct noop_pipe_screen *noop_screen = (struct noop_pipe_screen*)pscreen;
struct pipe_screen *screen = noop_screen->oscreen;
screen->query_memory_info(screen, info);
}
static struct disk_cache *noop_get_disk_shader_cache(struct pipe_screen *pscreen)
{
struct pipe_screen *screen = ((struct noop_pipe_screen*)pscreen)->oscreen;
return screen->get_disk_shader_cache(screen);
}
static void noop_finalize_nir(struct pipe_screen *pscreen, struct nir_shader *nir,
bool optimize)
{
struct pipe_screen *screen = ((struct noop_pipe_screen*)pscreen)->oscreen;
screen->finalize_nir(screen, nir, optimize);
}
static bool noop_check_resource_capability(struct pipe_screen *screen,
struct pipe_resource *resource,
unsigned bind)
{
return true;
}
static void noop_create_fence_win32(struct pipe_screen *screen,
struct pipe_fence_handle **fence,
void *handle,
const void *name,
enum pipe_fd_type type)
{
struct noop_pipe_screen *noop_screen = (struct noop_pipe_screen *)screen;
struct pipe_screen *oscreen = noop_screen->oscreen;
oscreen->create_fence_win32(oscreen, fence, handle, name, type);
}
static void noop_set_max_shader_compiler_threads(struct pipe_screen *screen,
unsigned max_threads)
{
}
static bool noop_is_parallel_shader_compilation_finished(struct pipe_screen *screen,
void *shader,
mesa_shader_stage shader_type)
{
return true;
}
static bool noop_is_dmabuf_modifier_supported(struct pipe_screen *screen,
uint64_t modifier, enum pipe_format format,
bool *external_only)
{
struct noop_pipe_screen *noop_screen = (struct noop_pipe_screen*)screen;
struct pipe_screen *oscreen = noop_screen->oscreen;
return oscreen->is_dmabuf_modifier_supported(oscreen, modifier, format, external_only);
}
static unsigned int noop_get_dmabuf_modifier_planes(struct pipe_screen *screen,
uint64_t modifier,
enum pipe_format format)
{
struct noop_pipe_screen *noop_screen = (struct noop_pipe_screen*)screen;
struct pipe_screen *oscreen = noop_screen->oscreen;
return oscreen->get_dmabuf_modifier_planes(oscreen, modifier, format);
}
static void noop_query_compression_rates(struct pipe_screen *screen,
enum pipe_format format, int max,
uint32_t *rates, int *count)
{
struct noop_pipe_screen *noop_screen = (struct noop_pipe_screen*)screen;
struct pipe_screen *oscreen = noop_screen->oscreen;
*count = 0;
if (oscreen->query_compression_rates)
oscreen->query_compression_rates(oscreen, format, max, rates, count);
}
static void noop_query_compression_modifiers(struct pipe_screen *screen,
enum pipe_format fmt, uint32_t rate,
int max, uint64_t *mods, int *count)
{
struct noop_pipe_screen *noop_screen = (struct noop_pipe_screen*)screen;
struct pipe_screen *oscreen = noop_screen->oscreen;
*count = 0;
if (oscreen->query_compression_modifiers)
oscreen->query_compression_modifiers(oscreen, fmt, rate, max, mods, count);
}
static void noop_get_driver_uuid(struct pipe_screen *screen, char *uuid)
{
struct noop_pipe_screen *noop_screen = (struct noop_pipe_screen*)screen;
struct pipe_screen *oscreen = noop_screen->oscreen;
oscreen->get_driver_uuid(oscreen, uuid);
}
static void noop_get_device_uuid(struct pipe_screen *screen, char *uuid)
{
struct noop_pipe_screen *noop_screen = (struct noop_pipe_screen*)screen;
struct pipe_screen *oscreen = noop_screen->oscreen;
oscreen->get_device_uuid(oscreen, uuid);
}
static void noop_get_device_luid(struct pipe_screen *screen, char *luid)
{
struct noop_pipe_screen *noop_screen = (struct noop_pipe_screen*)screen;
struct pipe_screen *oscreen = noop_screen->oscreen;
oscreen->get_device_luid(oscreen, luid);
}
static uint32_t noop_get_device_node_mask(struct pipe_screen *screen)
{
struct noop_pipe_screen *noop_screen = (struct noop_pipe_screen*)screen;
struct pipe_screen *oscreen = noop_screen->oscreen;
return oscreen->get_device_node_mask(oscreen);
}
static int noop_get_sparse_texture_virtual_page_size(struct pipe_screen *screen,
enum pipe_texture_target target,
bool multi_sample,
enum pipe_format format,
unsigned offset, unsigned size,
int *x, int *y, int *z)
{
struct noop_pipe_screen *noop_screen = (struct noop_pipe_screen*)screen;
struct pipe_screen *oscreen = noop_screen->oscreen;
return oscreen->get_sparse_texture_virtual_page_size(screen, target, multi_sample,
format, offset, size, x, y, z);
}
static void noop_query_dmabuf_modifiers(struct pipe_screen *screen,
enum pipe_format format, int max,
uint64_t *modifiers,
unsigned int *external_only, int *count)
{
struct noop_pipe_screen *noop_screen = (struct noop_pipe_screen*)screen;
struct pipe_screen *oscreen = noop_screen->oscreen;
oscreen->query_dmabuf_modifiers(oscreen, format, max, modifiers,
external_only, count);
}
static struct pipe_vertex_state *
noop_create_vertex_state(struct pipe_screen *screen,
struct pipe_vertex_buffer *buffer,
const struct pipe_vertex_element *elements,
unsigned num_elements,
struct pipe_resource *indexbuf,
uint32_t full_velem_mask)
{
struct pipe_vertex_state *state = CALLOC_STRUCT(pipe_vertex_state);
if (!state)
return NULL;
util_init_pipe_vertex_state(screen, buffer, elements, num_elements, indexbuf,
full_velem_mask, state);
return state;
}
static void noop_vertex_state_destroy(struct pipe_screen *screen,
struct pipe_vertex_state *state)
{
pipe_vertex_buffer_unreference(&state->input.vbuffer);
pipe_resource_reference(&state->input.indexbuf, NULL);
FREE(state);
}
static struct pipe_fence_handle *
noop_semaphore_create(struct pipe_screen *screen)
{
struct pipe_reference *f = MALLOC_STRUCT(pipe_reference);
f->count = 1;
return (struct pipe_fence_handle*)f;
}
static struct pipe_screen * noop_get_driver_pipe_screen(struct pipe_screen *_screen)
{
struct pipe_screen * screen = ((struct noop_pipe_screen*)_screen)->oscreen;
if (screen->get_driver_pipe_screen)
return screen->get_driver_pipe_screen(screen);
return screen;
}
struct pipe_screen *noop_screen_create(struct pipe_screen *oscreen)
{
struct noop_pipe_screen *noop_screen;
struct pipe_screen *screen;
if (!debug_get_option_noop()) {
return oscreen;
}
noop_screen = CALLOC_STRUCT(noop_pipe_screen);
if (!noop_screen) {
return NULL;
}
noop_screen->oscreen = oscreen;
screen = &noop_screen->pscreen;
screen->destroy = noop_destroy_screen;
screen->get_name = noop_get_name;
screen->get_vendor = noop_get_vendor;
screen->get_device_vendor = noop_get_device_vendor;
screen->is_format_supported = noop_is_format_supported;
screen->context_create = noop_create_context;
screen->resource_create = noop_resource_create;
screen->resource_from_handle = noop_resource_from_handle;
screen->resource_get_handle = noop_resource_get_handle;
if (oscreen->resource_get_param)
screen->resource_get_param = noop_resource_get_param;
screen->resource_destroy = noop_resource_destroy;
screen->flush_frontbuffer = noop_flush_frontbuffer;
screen->get_timestamp = noop_get_timestamp;
screen->fence_reference = noop_fence_reference;
screen->fence_finish = noop_fence_finish;
screen->query_memory_info = noop_query_memory_info;
screen->get_disk_shader_cache = noop_get_disk_shader_cache;
screen->finalize_nir = noop_finalize_nir;
if (screen->create_fence_win32)
screen->create_fence_win32 = noop_create_fence_win32;
screen->check_resource_capability = noop_check_resource_capability;
screen->set_max_shader_compiler_threads = noop_set_max_shader_compiler_threads;
screen->is_parallel_shader_compilation_finished = noop_is_parallel_shader_compilation_finished;
screen->is_dmabuf_modifier_supported = noop_is_dmabuf_modifier_supported;
screen->get_dmabuf_modifier_planes = noop_get_dmabuf_modifier_planes;
screen->get_driver_uuid = noop_get_driver_uuid;
screen->get_device_uuid = noop_get_device_uuid;
screen->get_device_luid = noop_get_device_luid;
screen->get_device_node_mask = noop_get_device_node_mask;
screen->query_dmabuf_modifiers = noop_query_dmabuf_modifiers;
screen->resource_create_with_modifiers = noop_resource_create_with_modifiers;
screen->create_vertex_state = noop_create_vertex_state;
screen->vertex_state_destroy = noop_vertex_state_destroy;
if (oscreen->get_sparse_texture_virtual_page_size)
screen->get_sparse_texture_virtual_page_size = noop_get_sparse_texture_virtual_page_size;
screen->query_compression_rates = noop_query_compression_rates;
screen->query_compression_modifiers = noop_query_compression_modifiers;
screen->get_driver_pipe_screen = noop_get_driver_pipe_screen;
if (oscreen->semaphore_create)
screen->semaphore_create = noop_semaphore_create;
/* copy all caps */
*(struct pipe_caps *)&screen->caps = oscreen->caps;
*(struct pipe_compute_caps *)&screen->compute_caps = oscreen->compute_caps;
memcpy((void *)screen->shader_caps, oscreen->shader_caps, sizeof(screen->shader_caps));
memcpy((void *)screen->nir_options, oscreen->nir_options, sizeof(screen->nir_options));
slab_create_parent(&noop_screen->pool_transfers,
sizeof(struct pipe_transfer), 64);
return screen;
}
@@ -0,0 +1,37 @@
/*
* Copyright 2010 Red Hat Inc.
*
* 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
* THE AUTHOR(S) 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 NOOP_PUBLIC_H
#define NOOP_PUBLIC_H
#ifdef __cplusplus
extern "C" {
#endif
struct pipe_screen;
PUBLIC struct pipe_screen *noop_screen_create(struct pipe_screen *screen);
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,477 @@
/*
* Copyright 2010 Red Hat Inc.
*
* 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
* THE AUTHOR(S) 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 <stdio.h>
#include <errno.h>
#include "pipe/p_defines.h"
#include "pipe/p_state.h"
#include "pipe/p_context.h"
#include "pipe/p_screen.h"
#include "util/u_memory.h"
#include "util/u_inlines.h"
#include "util/u_transfer.h"
static void noop_draw_vbo(struct pipe_context *ctx, 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)
{
}
static void noop_draw_vertex_state(struct pipe_context *ctx,
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)
{
}
static void noop_launch_grid(struct pipe_context *ctx,
const struct pipe_grid_info *info)
{
}
static void noop_set_blend_color(struct pipe_context *ctx,
const struct pipe_blend_color *state)
{
}
static void *noop_create_blend_state(struct pipe_context *ctx,
const struct pipe_blend_state *state)
{
return MALLOC(1);
}
static void *noop_create_dsa_state(struct pipe_context *ctx,
const struct pipe_depth_stencil_alpha_state *state)
{
return MALLOC(1);
}
static void *noop_create_rs_state(struct pipe_context *ctx,
const struct pipe_rasterizer_state *state)
{
return MALLOC(1);
}
static void *noop_create_sampler_state(struct pipe_context *ctx,
const struct pipe_sampler_state *state)
{
return MALLOC(1);
}
static struct pipe_sampler_view *noop_create_sampler_view(struct pipe_context *ctx,
struct pipe_resource *texture,
const struct pipe_sampler_view *state)
{
struct pipe_sampler_view *sampler_view = CALLOC_STRUCT(pipe_sampler_view);
if (!sampler_view)
return NULL;
/* initialize base object */
*sampler_view = *state;
sampler_view->texture = NULL;
pipe_resource_reference(&sampler_view->texture, texture);
pipe_reference_init(&sampler_view->reference, 1);
sampler_view->context = ctx;
return sampler_view;
}
static void noop_set_sampler_views(struct pipe_context *ctx,
mesa_shader_stage shader,
unsigned start, unsigned count,
unsigned unbind_num_trailing_slots,
struct pipe_sampler_view **views)
{
}
static void noop_bind_sampler_states(struct pipe_context *ctx,
mesa_shader_stage shader,
unsigned start, unsigned count,
void **states)
{
}
static void noop_set_clip_state(struct pipe_context *ctx,
const struct pipe_clip_state *state)
{
}
static void noop_set_polygon_stipple(struct pipe_context *ctx,
const struct pipe_poly_stipple *state)
{
}
static void noop_set_sample_mask(struct pipe_context *pipe, unsigned sample_mask)
{
}
static void noop_set_scissor_states(struct pipe_context *ctx,
unsigned start_slot,
unsigned num_scissors,
const struct pipe_scissor_state *state)
{
}
static void noop_set_stencil_ref(struct pipe_context *ctx,
const struct pipe_stencil_ref state)
{
}
static void noop_set_viewport_states(struct pipe_context *ctx,
unsigned start_slot,
unsigned num_viewports,
const struct pipe_viewport_state *state)
{
}
static void noop_set_framebuffer_state(struct pipe_context *ctx,
const struct pipe_framebuffer_state *state)
{
}
static void noop_set_constant_buffer(struct pipe_context *ctx,
mesa_shader_stage shader, uint index,
const struct pipe_constant_buffer *cb)
{
}
static void noop_set_inlinable_constants(struct pipe_context *ctx,
mesa_shader_stage shader,
uint num_values, uint32_t *values)
{
}
static void noop_sampler_view_destroy(struct pipe_context *ctx,
struct pipe_sampler_view *state)
{
pipe_resource_reference(&state->texture, NULL);
FREE(state);
}
static void noop_bind_state(struct pipe_context *ctx, void *state)
{
}
static void noop_delete_state(struct pipe_context *ctx, void *state)
{
FREE(state);
}
static void noop_set_vertex_buffers(struct pipe_context *ctx,
unsigned count,
const struct pipe_vertex_buffer *buffers)
{
}
static void *noop_create_vertex_elements(struct pipe_context *ctx,
unsigned count,
const struct pipe_vertex_element *state)
{
return MALLOC(1);
}
static void *noop_create_shader_state(struct pipe_context *ctx,
const struct pipe_shader_state *state)
{
return MALLOC(1);
}
static void *noop_create_compute_state(struct pipe_context *ctx,
const struct pipe_compute_state *state)
{
return MALLOC(1);
}
static struct pipe_stream_output_target *noop_create_stream_output_target(
struct pipe_context *ctx,
struct pipe_resource *res,
unsigned buffer_offset,
unsigned buffer_size)
{
struct pipe_stream_output_target *t = CALLOC_STRUCT(pipe_stream_output_target);
if (!t)
return NULL;
pipe_reference_init(&t->reference, 1);
pipe_resource_reference(&t->buffer, res);
t->buffer_offset = buffer_offset;
t->buffer_size = buffer_size;
return t;
}
static void noop_stream_output_target_destroy(struct pipe_context *ctx,
struct pipe_stream_output_target *t)
{
pipe_resource_reference(&t->buffer, NULL);
FREE(t);
}
static void noop_set_stream_output_targets(struct pipe_context *ctx,
unsigned num_targets,
struct pipe_stream_output_target **targets,
const unsigned *offsets,
enum mesa_prim output_prim)
{
}
static void noop_set_window_rectangles(struct pipe_context *ctx,
bool include,
unsigned num_rectangles,
const struct pipe_scissor_state *rects)
{
}
static void noop_set_shader_buffers(struct pipe_context *ctx,
mesa_shader_stage shader,
unsigned start_slot, unsigned count,
const struct pipe_shader_buffer *buffers,
unsigned writable_bitmask)
{
}
static void noop_set_shader_images(struct pipe_context *ctx,
mesa_shader_stage shader,
unsigned start_slot, unsigned count,
unsigned unbind_num_trailing_slots,
const struct pipe_image_view *images)
{
}
static void noop_render_condition( struct pipe_context *pipe,
struct pipe_query *query,
bool condition,
enum pipe_render_cond_flag mode )
{
}
static void noop_get_query_result_resource(struct pipe_context *pipe,
struct pipe_query *q,
enum pipe_query_flags flags,
enum pipe_query_value_type result_type,
int index,
struct pipe_resource *resource,
unsigned offset)
{
}
static void noop_set_min_samples( struct pipe_context *ctx,
unsigned min_samples )
{
}
static void noop_set_sample_locations( struct pipe_context *ctx,
size_t size, const uint8_t *locations )
{
}
static void noop_set_tess_state(struct pipe_context *ctx,
const float default_outer_level[4],
const float default_inner_level[2])
{
}
static void noop_clear_texture(struct pipe_context *pipe,
struct pipe_resource *res,
unsigned level,
const struct pipe_box *box,
const void *data)
{
}
static void noop_clear_buffer(struct pipe_context *pipe,
struct pipe_resource *res,
unsigned offset,
unsigned size,
const void *clear_value,
int clear_value_size)
{
}
static void noop_fence_server_sync(struct pipe_context *pipe,
struct pipe_fence_handle *fence,
uint64_t value)
{
}
static void noop_fence_server_signal(struct pipe_context *pipe,
struct pipe_fence_handle *fence,
uint64_t value)
{
}
static void noop_texture_barrier(struct pipe_context *ctx, unsigned flags)
{
}
static void noop_memory_barrier(struct pipe_context *ctx, unsigned flags)
{
}
static bool noop_resource_commit(struct pipe_context *ctx, struct pipe_resource *res,
unsigned level, struct pipe_box *box, bool commit)
{
return true;
}
static void noop_get_sample_position(struct pipe_context *context,
unsigned sample_count,
unsigned sample_index,
float *out_value)
{
}
static enum pipe_reset_status noop_get_device_reset_status(struct pipe_context *ctx)
{
return PIPE_NO_RESET;
}
static uint64_t noop_create_texture_handle(struct pipe_context *ctx,
struct pipe_sampler_view *view,
const struct pipe_sampler_state *state)
{
return 1;
}
static void noop_delete_texture_handle(struct pipe_context *ctx, uint64_t handle)
{
}
static void noop_make_texture_handle_resident(struct pipe_context *ctx,
uint64_t handle, bool resident)
{
}
static uint64_t noop_create_image_handle(struct pipe_context *ctx,
const struct pipe_image_view *image)
{
return 2;
}
static void noop_delete_image_handle(struct pipe_context *ctx, uint64_t handle)
{
}
static void noop_make_image_handle_resident(struct pipe_context *ctx, uint64_t handle,
unsigned access, bool resident)
{
}
static void noop_set_patch_vertices(struct pipe_context *ctx,
uint8_t patch_vertices)
{
}
void noop_init_state_functions(struct pipe_context *ctx);
void noop_init_state_functions(struct pipe_context *ctx)
{
ctx->create_blend_state = noop_create_blend_state;
ctx->create_depth_stencil_alpha_state = noop_create_dsa_state;
ctx->create_fs_state = noop_create_shader_state;
ctx->create_rasterizer_state = noop_create_rs_state;
ctx->create_sampler_state = noop_create_sampler_state;
ctx->create_sampler_view = noop_create_sampler_view;
ctx->create_vertex_elements_state = noop_create_vertex_elements;
ctx->create_compute_state = noop_create_compute_state;
ctx->create_tcs_state = noop_create_shader_state;
ctx->create_tes_state = noop_create_shader_state;
ctx->create_gs_state = noop_create_shader_state;
ctx->create_vs_state = noop_create_shader_state;
ctx->create_ts_state = noop_create_shader_state;
ctx->create_ms_state = noop_create_shader_state;
ctx->bind_blend_state = noop_bind_state;
ctx->bind_depth_stencil_alpha_state = noop_bind_state;
ctx->bind_sampler_states = noop_bind_sampler_states;
ctx->bind_fs_state = noop_bind_state;
ctx->bind_rasterizer_state = noop_bind_state;
ctx->bind_vertex_elements_state = noop_bind_state;
ctx->bind_compute_state = noop_bind_state;
ctx->bind_tcs_state = noop_bind_state;
ctx->bind_tes_state = noop_bind_state;
ctx->bind_gs_state = noop_bind_state;
ctx->bind_vs_state = noop_bind_state;
ctx->bind_ts_state = noop_bind_state;
ctx->bind_ms_state = noop_bind_state;
ctx->delete_blend_state = noop_delete_state;
ctx->delete_depth_stencil_alpha_state = noop_delete_state;
ctx->delete_fs_state = noop_delete_state;
ctx->delete_rasterizer_state = noop_delete_state;
ctx->delete_sampler_state = noop_delete_state;
ctx->delete_vertex_elements_state = noop_delete_state;
ctx->delete_compute_state = noop_delete_state;
ctx->delete_tcs_state = noop_delete_state;
ctx->delete_tes_state = noop_delete_state;
ctx->delete_gs_state = noop_delete_state;
ctx->delete_vs_state = noop_delete_state;
ctx->delete_ts_state = noop_delete_state;
ctx->delete_ms_state = noop_delete_state;
ctx->set_blend_color = noop_set_blend_color;
ctx->set_clip_state = noop_set_clip_state;
ctx->set_constant_buffer = noop_set_constant_buffer;
ctx->set_inlinable_constants = noop_set_inlinable_constants;
ctx->set_sampler_views = noop_set_sampler_views;
ctx->set_shader_buffers = noop_set_shader_buffers;
ctx->set_shader_images = noop_set_shader_images;
ctx->set_framebuffer_state = noop_set_framebuffer_state;
ctx->set_polygon_stipple = noop_set_polygon_stipple;
ctx->set_sample_mask = noop_set_sample_mask;
ctx->set_scissor_states = noop_set_scissor_states;
ctx->set_stencil_ref = noop_set_stencil_ref;
ctx->set_vertex_buffers = noop_set_vertex_buffers;
ctx->set_viewport_states = noop_set_viewport_states;
ctx->set_window_rectangles = noop_set_window_rectangles;
ctx->sampler_view_destroy = noop_sampler_view_destroy;
ctx->sampler_view_release = u_default_sampler_view_release;
ctx->draw_vbo = noop_draw_vbo;
ctx->draw_vertex_state = noop_draw_vertex_state;
ctx->launch_grid = noop_launch_grid;
ctx->draw_mesh_tasks = noop_launch_grid;;
ctx->create_stream_output_target = noop_create_stream_output_target;
ctx->stream_output_target_destroy = noop_stream_output_target_destroy;
ctx->set_stream_output_targets = noop_set_stream_output_targets;
ctx->render_condition = noop_render_condition;
ctx->get_query_result_resource = noop_get_query_result_resource;
ctx->set_min_samples = noop_set_min_samples;
ctx->set_sample_locations = noop_set_sample_locations;
ctx->set_tess_state = noop_set_tess_state;
ctx->clear_texture = noop_clear_texture;
ctx->clear_buffer = noop_clear_buffer;
ctx->fence_server_sync = noop_fence_server_sync;
ctx->fence_server_signal = noop_fence_server_signal;
ctx->texture_barrier = noop_texture_barrier;
ctx->memory_barrier = noop_memory_barrier;
ctx->resource_commit = noop_resource_commit;
ctx->get_sample_position = noop_get_sample_position;
ctx->get_device_reset_status = noop_get_device_reset_status;
ctx->create_texture_handle = noop_create_texture_handle;
ctx->delete_texture_handle = noop_delete_texture_handle;
ctx->make_texture_handle_resident = noop_make_texture_handle_resident;
ctx->create_image_handle = noop_create_image_handle;
ctx->delete_image_handle = noop_delete_image_handle;
ctx->make_image_handle_resident = noop_make_image_handle_resident;
ctx->set_patch_vertices = noop_set_patch_vertices;
}
+55
View File
@@ -0,0 +1,55 @@
TRACE PIPE DRIVER
= About =
This directory contains a Gallium3D trace debugger pipe driver.
It can traces all incoming calls.
= Usage =
== Tracing ==
For tracing then do
GALLIUM_TRACE=tri.trace trivial/tri
which should create a tri.trace file, which is an XML file. You can view copying
trace.xsl to the same directory, and opening with a XSLT capable browser such as
Firefox or Internet Explorer.
For long traces you can use the
src/gallium/tools/trace/dump.py tri.trace | less -R
== Remote debugging ==
For remote debugging see:
src/gallium/auxiliary/driver_rbug/README
= Integrating =
You can integrate the trace pipe driver either inside the gallium frontend or the
target. The procedure on both cases is the same. Let's assume you have a
pipe_screen obtained by the usual means (variable and function names are just
for illustration purposes):
real_screen = real_screen_create(...);
The trace screen is then created by doing
trace_screen = trace_screen_create(real_screen);
You can then simply use trace_screen instead of real_screen.
You can create as many contexts you wish from trace_screen::context_create they
are automatically wrapped by trace_screen.
--
Jose Fonseca <[email protected]>
Jakob Bornecrantz <[email protected]>
+305
View File
@@ -0,0 +1,305 @@
#!/usr/bin/env python3
# coding=utf-8
##########################################################################
#
# enums2names - Parse and convert enums to translator code
# (C) Copyright 2021 Matti 'ccr' Hämäläinen <[email protected]>
#
# 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, 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 ITS 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.
#
##########################################################################
import sys
import os.path
import re
import signal
import argparse
import textwrap
assert sys.version_info >= (3, 6)
#
# List of enums we wish to include in output.
# NOTE: This needs to be updated if such enums are added.
#
lst_enum_include = [
"pipe_texture_target",
"pipe_shader_ir",
"pipe_map_flags",
"pipe_video_cap",
"pipe_video_profile",
"pipe_video_entrypoint",
"pipe_video_vpp_orientation",
"pipe_video_vpp_blend_mode",
"pipe_resource_param",
"pipe_fd_type",
"pipe_blendfactor",
"pipe_blend_func",
"pipe_logicop",
]
###
### Utility functions
###
## Fatal error handler
def pkk_fatal(smsg):
print("ERROR: "+ smsg)
sys.exit(1)
## Handler for SIGINT signals
def pkk_signal_handler(signal, frame):
print("\nQuitting due to SIGINT / Ctrl+C!")
sys.exit(1)
## Argument parser subclass
class PKKArgumentParser(argparse.ArgumentParser):
def print_help(self):
print("enums2names - Parse and convert enums to translator code\n"
"(C) Copyright 2021 Matti 'ccr' Hämäläinen <[email protected]>\n")
super().print_help()
def error(self, msg):
self.print_help()
print(f"\nERROR: {msg}", file=sys.stderr)
sys.exit(2)
def pkk_get_argparser():
optparser = PKKArgumentParser(
usage="%(prog)s [options] <infile|->\n"
"example: %(prog)s ../../include/pipe/p_defines.h -C tr_util.c -H tr_util.h"
)
optparser.add_argument("in_files",
type=str,
metavar="infiles",
nargs="+",
help="path to input header files (or '-' for stdin)")
optparser.add_argument("-C",
type=str,
metavar="outfile",
dest="out_source",
help="output C source file")
optparser.add_argument("-H",
type=str,
metavar="outfile",
dest="out_header",
help="output H header file (the basename will be use to include the header in the C source file)")
return optparser
class PKKHeaderParser:
def __init__(self, nfilename):
self.filename = nfilename
self.enums = {}
self.state = 0
self.nline = 0
self.mdata = []
self.start = 0
self.name = None
self.in_multiline_comment = False
def error(self, msg):
pkk_fatal(f"{self.filename}:{self.nline} : {msg}")
def parse_line(self, sline: str):
start = sline.find('/*')
end = sline.find('*/')
if not self.in_multiline_comment and start >= 0:
if end >= 0:
assert end > start
sline = sline[:start] + sline[end + 2:]
else:
sline = sline[:start]
self.in_multiline_comment = True
elif self.in_multiline_comment and end >= 0:
self.in_multiline_comment = False
sline = sline[end + 2:]
elif self.in_multiline_comment:
return
# A kingdom for Py3.8 := operator ...
smatch = re.match(r'^enum\s+([A-Za-z0-9_]+)\s+.*;', sline)
if smatch:
pass
else:
smatch = re.match(r'^enum\s+([A-Za-z0-9_]+)', sline)
if smatch:
stmp = smatch.group(1)
if self.state != 0:
self.error(f"enum '{stmp}' starting inside another enum '{self.name}'")
self.name = stmp
self.state = 1
self.start = self.nline
self.mdata = []
else:
smatch = re.match(r'^}(\s*|\s*[A-Z][A-Z_]+\s*);', sline)
if smatch:
if self.state == 1:
if self.name in self.enums:
self.error("duplicate enum definition '{}', lines {} - {} vs {} - {}".format(
self.name, self.enums[self.name]["start"], self.enums[self.name]["end"],
self.start, self.nline))
self.enums[self.name] = {
"data": self.mdata,
"start": self.start,
"end": self.nline
}
self.state = 0
elif self.state == 1:
smatch = re.match(r'([A-Za-z0-9_]+)\s*=\s*(.+)\s*,?', sline)
if smatch:
self.mdata.append(smatch.group(1))
else:
smatch = re.match(r'([A-Za-z0-9_]+)\s*,?', sline)
if smatch:
self.mdata.append(smatch.group(1))
def parse_file(self, fh):
self.nline = 0
for line in fh:
self.nline += 1
self.parse_line(line.strip())
return self.enums
def pkk_output_header(fh):
prototypes = [f"const char *\n"
f"tr_util_{name}_name(enum {name} value);\n" for name in lst_enum_include]
print(textwrap.dedent("""\
/*
* File generated with {program}, please do not edit manually.
*/
#ifndef {include_header_guard}
#define {include_header_guard}
#include "pipe/p_defines.h"
#include "pipe/p_video_enums.h"
#ifdef __cplusplus
extern "C" {{
#endif
{prototypes}
#ifdef __cplusplus
}}
#endif
#endif /* {include_header_guard} */\
""").format(
program=pkk_progname,
include_header_guard=re.sub(r'[^A-Z]', '_', os.path.basename(pkk_cfg.out_header).upper()),
prototypes="".join(prototypes)
), file=fh)
def pkk_output_source(fh):
print(textwrap.dedent("""\
/*
* File generated with {program}, please do not edit manually.
*/
#include "{include_file}"
""").format(
program=pkk_progname,
include_file=os.path.basename(pkk_cfg.out_header),
), file=fh)
for name in lst_enum_include:
cases = [f" case {eid}: return \"{eid}\";\n"
for eid in enums[name]["data"]]
print(textwrap.dedent("""\
const char *
tr_util_{name}_name(enum {name} value)
{{
switch (value) {{
{cases}
default: return "{ucname}_UNKNOWN";
}}
}}
""").format(
name=name,
ucname=name.upper(),
cases="".join(cases)
), file=fh)
###
### Main program starts
###
if __name__ == "__main__":
signal.signal(signal.SIGINT, pkk_signal_handler)
### Parse arguments
pkk_progname = sys.argv[0]
optparser = pkk_get_argparser()
pkk_cfg = optparser.parse_args()
### Parse input files
enums = {}
for file in pkk_cfg.in_files:
hdrparser = PKKHeaderParser(file)
try:
if file != "-":
with open(file, "r", encoding="UTF-8") as fh:
enums.update(hdrparser.parse_file(fh))
else:
enums.update(hdrparser.parse_file(sys.stdin))
break
except OSError as e:
pkk_fatal(str(e))
### Check if any of the required enums are missing
errors = False
for name in lst_enum_include:
if name not in enums:
print(f"ERROR: Missing enum '{name}'!")
errors = True
if errors:
pkk_fatal(f"Errors in input. Edit this script ({pkk_progname}) to add/remove included enums.")
### Perform output
if pkk_cfg.out_header:
with open(pkk_cfg.out_header, "w", encoding="UTF-8") as fh:
pkk_output_header(fh)
if pkk_cfg.out_source:
with open(pkk_cfg.out_source, "w", encoding="UTF-8") as fh:
pkk_output_source(fh)
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,95 @@
/**************************************************************************
*
* Copyright 2008 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 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 ITS 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 TR_CONTEXT_H_
#define TR_CONTEXT_H_
#include "util/compiler.h"
#include "util/u_debug.h"
#include "util/hash_table.h"
#include "pipe/p_context.h"
#include "pipe/p_video_codec.h"
#include "util/u_threaded_context.h"
#include "tr_screen.h"
#ifdef __cplusplus
extern "C" {
#endif
struct trace_screen;
struct trace_context
{
struct pipe_context base;
struct hash_table blend_states;
struct hash_table rasterizer_states;
struct hash_table depth_stencil_alpha_states;
struct pipe_context *pipe;
tc_replace_buffer_storage_func replace_buffer_storage;
tc_create_fence_func create_fence;
struct pipe_framebuffer_state unwrapped_state;
bool seen_fb_state;
bool threaded;
};
void
trace_context_check(const struct pipe_context *pipe);
struct pipe_context *
trace_get_possibly_threaded_context(struct pipe_context *pipe);
static inline struct trace_context *
trace_context(struct pipe_context *pipe)
{
assert(pipe);
#if MESA_DEBUG
trace_context_check(pipe);
#endif
return (struct trace_context *)pipe;
}
struct pipe_context *
trace_context_create(struct trace_screen *tr_scr,
struct pipe_context *pipe);
struct pipe_context *
trace_context_create_threaded(struct pipe_screen *screen, struct pipe_context *pipe,
tc_replace_buffer_storage_func *replace_buffer,
struct threaded_context_options *options);
#ifdef __cplusplus
}
#endif
#endif /* TR_CONTEXT_H_ */
@@ -0,0 +1,662 @@
/**************************************************************************
*
* Copyright 2008 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 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 ITS 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.
*
**************************************************************************/
/**
* @file
* Trace dumping functions.
*
* For now we just use standard XML for dumping the trace calls, as this is
* simple to write, parse, and visually inspect, but the actual representation
* is abstracted out of this file, so that we can switch to a binary
* representation if/when it becomes justified.
*
* @author Jose Fonseca <[email protected]>
*/
#include "util/detect.h"
#include <stdio.h>
#include <stdlib.h>
/* for access() */
#ifdef _WIN32
# include <io.h>
#endif
#include "util/compiler.h"
#include "util/u_thread.h"
#include "util/os_time.h"
#include "util/simple_mtx.h"
#include "util/u_debug.h"
#include "util/u_memory.h"
#include "util/u_string.h"
#include "util/u_math.h"
#include "util/format/u_format.h"
#include "compiler/nir/nir.h"
#include "tr_dump.h"
#include "tr_screen.h"
#include "tr_texture.h"
static bool close_stream = false;
static FILE *stream = NULL;
static simple_mtx_t call_mutex = SIMPLE_MTX_INITIALIZER;
static long unsigned call_no = 0;
static bool dumping = false;
static long nir_count = 0;
static bool trigger_active = true;
static char *trigger_filename = NULL;
void
trace_dump_trigger_active(bool active)
{
trigger_active = active;
}
void
trace_dump_check_trigger(void)
{
if (!trigger_filename)
return;
simple_mtx_lock(&call_mutex);
if (trigger_active) {
trigger_active = false;
} else {
if (!access(trigger_filename, 2 /* W_OK but compiles on Windows */)) {
if (!unlink(trigger_filename)) {
trigger_active = true;
} else {
fprintf(stderr, "error removing trigger file\n");
trigger_active = false;
}
}
}
simple_mtx_unlock(&call_mutex);
}
bool
trace_dump_is_triggered(void)
{
return trigger_active && !!trigger_filename;
}
static inline void
trace_dump_write(const char *buf, size_t size)
{
if (stream && trigger_active) {
fwrite(buf, size, 1, stream);
}
}
static inline void
trace_dump_writes(const char *s)
{
trace_dump_write(s, strlen(s));
}
static inline void
trace_dump_writef(const char *format, ...)
{
static char buf[1024];
unsigned len;
va_list ap;
va_start(ap, format);
len = vsnprintf(buf, sizeof(buf), format, ap);
va_end(ap);
trace_dump_write(buf, len);
}
static inline void
trace_dump_escape(const char *str)
{
const unsigned char *p = (const unsigned char *)str;
unsigned char c;
while((c = *p++) != 0) {
if(c == '<')
trace_dump_writes("&lt;");
else if(c == '>')
trace_dump_writes("&gt;");
else if(c == '&')
trace_dump_writes("&amp;");
else if(c == '\'')
trace_dump_writes("&apos;");
else if(c == '\"')
trace_dump_writes("&quot;");
else if(c >= 0x20 && c <= 0x7e)
trace_dump_writef("%c", c);
else
trace_dump_writef("&#%u;", c);
}
}
static inline void
trace_dump_indent(unsigned level)
{
unsigned i;
for(i = 0; i < level; ++i)
trace_dump_writes("\t");
}
static inline void
trace_dump_newline(void)
{
trace_dump_writes("\n");
}
static inline void
trace_dump_tag_begin(const char *name)
{
trace_dump_writes("<");
trace_dump_writes(name);
trace_dump_writes(">");
}
static inline void
trace_dump_tag_begin1(const char *name,
const char *attr1, const char *value1)
{
trace_dump_writes("<");
trace_dump_writes(name);
trace_dump_writes(" ");
trace_dump_writes(attr1);
trace_dump_writes("='");
trace_dump_escape(value1);
trace_dump_writes("'>");
}
static inline void
trace_dump_tag_end(const char *name)
{
trace_dump_writes("</");
trace_dump_writes(name);
trace_dump_writes(">");
}
void
trace_dump_trace_flush(void)
{
if (stream) {
fflush(stream);
}
}
static void
trace_dump_trace_close(void)
{
if (stream) {
trigger_active = true;
trace_dump_writes("</trace>\n");
if (close_stream) {
fclose(stream);
close_stream = false;
stream = NULL;
}
call_no = 0;
free(trigger_filename);
}
}
static void
trace_dump_call_time(int64_t time)
{
if (stream) {
trace_dump_indent(2);
trace_dump_tag_begin("time");
trace_dump_int(time);
trace_dump_tag_end("time");
trace_dump_newline();
}
}
bool
trace_dump_trace_begin(void)
{
const char *filename;
filename = debug_get_option("GALLIUM_TRACE", NULL);
if (!filename)
return false;
nir_count = debug_get_num_option("GALLIUM_TRACE_NIR", 32);
if (!stream) {
if (strcmp(filename, "stderr") == 0) {
close_stream = false;
stream = stderr;
}
else if (strcmp(filename, "stdout") == 0) {
close_stream = false;
stream = stdout;
}
else {
close_stream = true;
stream = fopen(filename, "wt");
if (!stream)
return false;
}
trace_dump_writes("<?xml version='1.0' encoding='UTF-8'?>\n");
trace_dump_writes("<?xml-stylesheet type='text/xsl' href='trace.xsl'?>\n");
trace_dump_writes("<trace version='0.1'>\n");
/* Many applications don't exit cleanly, others may create and destroy a
* screen multiple times, so we only write </trace> tag and close at exit
* time.
*/
atexit(trace_dump_trace_close);
const char *trigger = debug_get_option("GALLIUM_TRACE_TRIGGER", NULL);
if (trigger && __normal_user()) {
trigger_filename = strdup(trigger);
trigger_active = false;
} else
trigger_active = true;
}
return true;
}
bool trace_dump_trace_enabled(void)
{
return stream ? true : false;
}
/*
* Call lock
*/
void trace_dump_call_lock(void)
{
simple_mtx_lock(&call_mutex);
}
void trace_dump_call_unlock(void)
{
simple_mtx_unlock(&call_mutex);
}
/*
* Dumping control
*/
void trace_dumping_start_locked(void)
{
dumping = true;
}
void trace_dumping_stop_locked(void)
{
dumping = false;
}
bool trace_dumping_enabled_locked(void)
{
return dumping;
}
void trace_dumping_start(void)
{
simple_mtx_lock(&call_mutex);
trace_dumping_start_locked();
simple_mtx_unlock(&call_mutex);
}
void trace_dumping_stop(void)
{
simple_mtx_lock(&call_mutex);
trace_dumping_stop_locked();
simple_mtx_unlock(&call_mutex);
}
bool trace_dumping_enabled(void)
{
bool ret;
simple_mtx_lock(&call_mutex);
ret = trace_dumping_enabled_locked();
simple_mtx_unlock(&call_mutex);
return ret;
}
/*
* Dump functions
*/
static int64_t call_start_time = 0;
void trace_dump_call_begin_locked(const char *klass, const char *method)
{
if (!dumping)
return;
++call_no;
trace_dump_indent(1);
trace_dump_writes("<call no=\'");
trace_dump_writef("%lu", call_no);
trace_dump_writes("\' class=\'");
trace_dump_escape(klass);
trace_dump_writes("\' method=\'");
trace_dump_escape(method);
trace_dump_writes("\'>");
trace_dump_newline();
call_start_time = os_time_get();
}
void trace_dump_call_end_locked(void)
{
int64_t call_end_time;
if (!dumping)
return;
call_end_time = os_time_get();
trace_dump_call_time(call_end_time - call_start_time);
trace_dump_indent(1);
trace_dump_tag_end("call");
trace_dump_newline();
fflush(stream);
}
void trace_dump_call_begin(const char *klass, const char *method)
{
simple_mtx_lock(&call_mutex);
trace_dump_call_begin_locked(klass, method);
}
void trace_dump_call_end(void)
{
trace_dump_call_end_locked();
simple_mtx_unlock(&call_mutex);
}
void trace_dump_arg_begin(const char *name)
{
if (!dumping)
return;
trace_dump_indent(2);
trace_dump_tag_begin1("arg", "name", name);
}
void trace_dump_arg_end(void)
{
if (!dumping)
return;
trace_dump_tag_end("arg");
trace_dump_newline();
}
void trace_dump_ret_begin(void)
{
if (!dumping)
return;
trace_dump_indent(2);
trace_dump_tag_begin("ret");
}
void trace_dump_ret_end(void)
{
if (!dumping)
return;
trace_dump_tag_end("ret");
trace_dump_newline();
}
void trace_dump_bool(bool value)
{
if (!dumping)
return;
trace_dump_writef("<bool>%c</bool>", value ? '1' : '0');
}
void trace_dump_int(int64_t value)
{
if (!dumping)
return;
trace_dump_writef("<int>%" PRIi64 "</int>", value);
}
void trace_dump_uint(uint64_t value)
{
if (!dumping)
return;
trace_dump_writef("<uint>%" PRIu64 "</uint>", value);
}
void trace_dump_float(double value)
{
if (!dumping)
return;
trace_dump_writef("<float>%g</float>", value);
}
void trace_dump_bytes(const void *data,
size_t size)
{
static const char hex_table[16] = "0123456789ABCDEF";
const uint8_t *p = data;
size_t i;
if (!dumping)
return;
trace_dump_writes("<bytes>");
for(i = 0; i < size; ++i) {
uint8_t byte = *p++;
char hex[2];
hex[0] = hex_table[byte >> 4];
hex[1] = hex_table[byte & 0xf];
trace_dump_write(hex, 2);
}
trace_dump_writes("</bytes>");
}
void trace_dump_box_bytes(const void *data,
struct pipe_resource *resource,
const struct pipe_box *box,
unsigned stride,
uint64_t slice_stride)
{
enum pipe_format format = resource->format;
uint64_t size;
assert(box->height > 0);
assert(box->depth > 0);
size = util_format_get_nblocksx(format, box->width ) *
(uint64_t)util_format_get_blocksize(format) +
(util_format_get_nblocksy(format, box->height) - 1) *
(uint64_t)stride + (box->depth - 1) * slice_stride;
/*
* Only dump buffer transfers to avoid huge files.
* TODO: Make this run-time configurable
*/
if (resource->target != PIPE_BUFFER) {
size = 0;
}
assert(size <= SIZE_MAX);
trace_dump_bytes(data, size);
}
void trace_dump_string(const char *str)
{
if (!dumping)
return;
trace_dump_writes("<string>");
trace_dump_escape(str);
trace_dump_writes("</string>");
}
void trace_dump_enum(const char *value)
{
if (!dumping)
return;
trace_dump_writes("<enum>");
trace_dump_escape(value);
trace_dump_writes("</enum>");
}
void trace_dump_array_begin(void)
{
if (!dumping)
return;
trace_dump_writes("<array>");
}
void trace_dump_array_end(void)
{
if (!dumping)
return;
trace_dump_writes("</array>");
}
void trace_dump_elem_begin(void)
{
if (!dumping)
return;
trace_dump_writes("<elem>");
}
void trace_dump_elem_end(void)
{
if (!dumping)
return;
trace_dump_writes("</elem>");
}
void trace_dump_struct_begin(const char *name)
{
if (!dumping)
return;
trace_dump_writef("<struct name='%s'>", name);
}
void trace_dump_struct_end(void)
{
if (!dumping)
return;
trace_dump_writes("</struct>");
}
void trace_dump_member_begin(const char *name)
{
if (!dumping)
return;
trace_dump_writef("<member name='%s'>", name);
}
void trace_dump_member_end(void)
{
if (!dumping)
return;
trace_dump_writes("</member>");
}
void trace_dump_null(void)
{
if (!dumping)
return;
trace_dump_writes("<null/>");
}
void trace_dump_ptr(const void *value)
{
if (!dumping)
return;
if(value)
trace_dump_writef("<ptr>0x%08lx</ptr>", (unsigned long)(uintptr_t)value);
else
trace_dump_null();
}
void trace_dump_transfer_ptr(struct pipe_transfer *_transfer)
{
if (!dumping)
return;
if (_transfer) {
struct trace_transfer *tr_tran = trace_transfer(_transfer);
trace_dump_ptr(tr_tran->transfer);
} else {
trace_dump_null();
}
}
void trace_dump_nir(struct nir_shader *nir)
{
if (!dumping)
return;
if (--nir_count < 0) {
fputs("<string>...</string>", stream);
return;
}
// NIR doesn't have a print to string function. Use CDATA and hope for the
// best.
if (stream) {
fputs("<string><![CDATA[", stream);
nir_print_shader(nir, stream);
fputs("]]></string>", stream);
}
}
@@ -0,0 +1,252 @@
/**************************************************************************
*
* Copyright 2008 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 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 ITS 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.
*
**************************************************************************/
/**
* @file
* Trace data dumping primitives.
*/
#ifndef TR_DUMP_H
#define TR_DUMP_H
#include "util/compiler.h"
#include "util/format/u_formats.h"
struct pipe_resource;
struct pipe_surface;
struct pipe_transfer;
struct pipe_box;
struct nir_shader;
/*
* Low level dumping controls.
*
* Opening the trace file and checking if that is opened.
*/
bool trace_dump_trace_begin(void);
bool trace_dump_trace_enabled(void);
void trace_dump_trace_flush(void);
/*
* Lock and unlock the call mutex.
*
* It used by the none locked version of dumping control
* and begin/end call dump functions.
*
* Begin takes the lock while end unlocks it. Use the _locked
* version to avoid locking/unlocking it.
*/
void trace_dump_call_lock(void);
void trace_dump_call_unlock(void);
/*
* High level dumping control.
*/
void trace_dumping_start_locked(void);
void trace_dumping_stop_locked(void);
bool trace_dumping_enabled_locked(void);
void trace_dumping_start(void);
void trace_dumping_stop(void);
bool trace_dumping_enabled(void);
void trace_dump_call_begin_locked(const char *klass, const char *method);
void trace_dump_call_end_locked(void);
void trace_dump_call_begin(const char *klass, const char *method);
void trace_dump_call_end(void);
void trace_dump_arg_begin(const char *name);
void trace_dump_arg_end(void);
void trace_dump_ret_begin(void);
void trace_dump_ret_end(void);
void trace_dump_bool(bool value);
void trace_dump_int(int64_t value);
void trace_dump_uint(uint64_t value);
void trace_dump_float(double value);
void trace_dump_bytes(const void *data, size_t size);
void trace_dump_box_bytes(const void *data,
struct pipe_resource *resource,
const struct pipe_box *box,
unsigned stride,
uint64_t slice_stride);
void trace_dump_string(const char *str);
void trace_dump_enum(const char *value);
void trace_dump_array_begin(void);
void trace_dump_array_end(void);
void trace_dump_elem_begin(void);
void trace_dump_elem_end(void);
void trace_dump_struct_begin(const char *name);
void trace_dump_struct_end(void);
void trace_dump_member_begin(const char *name);
void trace_dump_member_end(void);
void trace_dump_null(void);
void trace_dump_ptr(const void *value);
void trace_dump_transfer_ptr(struct pipe_transfer *_transfer);
void trace_dump_nir(struct nir_shader *nir);
void trace_dump_trigger_active(bool active);
void trace_dump_check_trigger(void);
bool trace_dump_is_triggered(void);
/*
* Code saving macros.
*/
#define trace_dump_arg(_type, _arg) \
do { \
trace_dump_arg_begin(#_arg); \
trace_dump_##_type(_arg); \
trace_dump_arg_end(); \
} while(0)
#define trace_dump_arg_enum(_type, _arg) \
do { \
trace_dump_arg_begin(#_arg); \
trace_dump_enum(tr_util_##_type##_name(_arg)); \
trace_dump_arg_end(); \
} while(0)
#define trace_dump_arg_struct(_type, _arg) \
do { \
trace_dump_arg_begin(#_arg); \
trace_dump_##_type(&_arg); \
trace_dump_arg_end(); \
} while(0)
#define trace_dump_ret(_type, _arg) \
do { \
trace_dump_ret_begin(); \
trace_dump_##_type(_arg); \
trace_dump_ret_end(); \
} while(0)
#define trace_dump_array_impl(_type, _obj, _size, _prefix) \
do { \
void *objptr = (void*)(_obj); \
if (objptr) { \
size_t idx; \
trace_dump_array_begin(); \
for(idx = 0; idx < (_size); ++idx) { \
trace_dump_elem_begin(); \
trace_dump_##_type(_prefix(_obj)[idx]); \
trace_dump_elem_end(); \
} \
trace_dump_array_end(); \
} else { \
trace_dump_null(); \
} \
} while(0)
#define trace_dump_array(_type, _obj, _size) \
trace_dump_array_impl(_type, _obj, _size, );
#define trace_dump_array_val(_type, _obj, _size) \
trace_dump_array_impl(_type, _obj, _size, *);
#define trace_dump_struct_array(_type, _obj, _size) \
do { \
void *objptr = (void*)(_obj); \
if (objptr) { \
size_t idx; \
trace_dump_array_begin(); \
for(idx = 0; idx < (_size); ++idx) { \
trace_dump_elem_begin(); \
trace_dump_##_type(&(_obj)[idx]); \
trace_dump_elem_end(); \
} \
trace_dump_array_end(); \
} else { \
trace_dump_null(); \
} \
} while(0)
#define trace_dump_member(_type, _obj, _member) \
do { \
trace_dump_member_begin(#_member); \
trace_dump_##_type((_obj)->_member); \
trace_dump_member_end(); \
} while(0)
#define trace_dump_member_val(_type, _obj, _member) \
do { \
trace_dump_member_begin(#_member); \
trace_dump_##_type(&(_obj)->_member); \
trace_dump_member_end(); \
} while(0)
#define trace_dump_member_enum(_type, _obj, _member) \
do { \
trace_dump_member_begin(#_member); \
trace_dump_enum(tr_util_##_type##_name((_obj)->_member)); \
trace_dump_member_end(); \
} while(0)
#define trace_dump_member_struct(_type, _obj, _member) \
do { \
trace_dump_member_begin(#_member); \
trace_dump_##_type(&((_obj)->_member)); \
trace_dump_member_end(); \
} while(0)
#define trace_dump_arg_array(_type, _arg, _size) \
do { \
trace_dump_arg_begin(#_arg); \
trace_dump_array(_type, _arg, _size); \
trace_dump_arg_end(); \
} while(0)
#define trace_dump_arg_array_val(_type, _arg, _size) \
do { \
trace_dump_arg_begin(#_arg); \
trace_dump_array_val(_type, _arg, _size); \
trace_dump_arg_end(); \
} while(0)
#define trace_dump_ret_array(_type, _arg, _size) \
do { \
trace_dump_ret_begin(); \
trace_dump_array(_type, _arg, _size); \
trace_dump_ret_end(); \
} while(0)
#define trace_dump_ret_array_val(_type, _arg, _size) \
do { \
trace_dump_ret_begin(); \
trace_dump_array_val(_type, _arg, _size); \
trace_dump_ret_end(); \
} while(0)
#define trace_dump_member_array(_type, _obj, _member) \
do { \
trace_dump_member_begin(#_member); \
trace_dump_array(_type, (_obj)->_member, sizeof((_obj)->_member)/sizeof((_obj)->_member[0])); \
trace_dump_member_end(); \
} while(0)
#endif /* TR_DUMP_H */
@@ -0,0 +1,75 @@
/**************************************************************************
*
* Copyright 2013 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 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 ITS 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 TR_DUMP_DEFINES_H_
#define TR_DUMP_DEFINES_H_
#include "util/compiler.h"
#include "util/format/u_format.h"
#include "util/u_dump.h"
#include "tr_dump.h"
static inline void
trace_dump_format(enum pipe_format format)
{
if (!trace_dumping_enabled_locked())
return;
trace_dump_enum(util_format_name(format));
}
static inline void
trace_dump_chroma_format(enum pipe_video_chroma_format chroma_format)
{
if (!trace_dumping_enabled_locked())
return;
trace_dump_enum(util_chroma_format_name(chroma_format));
}
static inline void
trace_dump_query_type(unsigned value)
{
if (!trace_dumping_enabled_locked())
return;
trace_dump_enum(util_str_query_type(value, false));
}
static inline void
trace_dump_query_flags(unsigned value)
{
if (!trace_dumping_enabled_locked())
return;
trace_dump_enum(util_str_query_type(value, false));
}
#endif /* TR_DUMP_DEFINES_H_ */
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,126 @@
/**************************************************************************
*
* Copyright 2008 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 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 ITS 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 TR_DUMP_STATE_H_
#define TR_DUMP_STATE_H_
#include "pipe/p_state.h"
#include "pipe/p_shader_tokens.h"
#include "pipe/p_video_codec.h"
struct winsys_handle;
void trace_dump_resource_template(const struct pipe_resource *templat);
void trace_dump_video_codec_template(const struct pipe_video_codec *templat);
void trace_dump_video_buffer_template(const struct pipe_video_buffer *templat);
void trace_dump_pipe_picture_desc(const struct pipe_picture_desc *picture);
void trace_dump_pipe_vpp_blend(const struct pipe_vpp_blend *blend);
void trace_dump_pipe_vpp_desc(const struct pipe_vpp_desc *process_properties);
void trace_dump_box(const struct pipe_box *box);
void trace_dump_u_rect(const struct u_rect *rect);
void trace_dump_rasterizer_state(const struct pipe_rasterizer_state *state);
void trace_dump_poly_stipple(const struct pipe_poly_stipple *state);
void trace_dump_viewport_state(const struct pipe_viewport_state *state);
void trace_dump_scissor_state(const struct pipe_scissor_state *state);
void trace_dump_clip_state(const struct pipe_clip_state *state);
void trace_dump_token(const struct tgsi_token *token);
void trace_dump_shader_state(const struct pipe_shader_state *state);
void trace_dump_compute_state(const struct pipe_compute_state *state);
void trace_dump_depth_stencil_alpha_state(const struct pipe_depth_stencil_alpha_state *state);
void trace_dump_blend_state(const struct pipe_blend_state *state);
void trace_dump_blend_color(const struct pipe_blend_color *state);
void trace_dump_stencil_ref(const struct pipe_stencil_ref *state);
void trace_dump_framebuffer_state(const struct pipe_framebuffer_state *state);
void trace_dump_framebuffer_state_deep(const struct pipe_framebuffer_state *state);
void trace_dump_sampler_state(const struct pipe_sampler_state *state);
void trace_dump_sampler_view_template(const struct pipe_sampler_view *view);
void trace_dump_surface(const struct pipe_surface *surface);
void trace_dump_surface_template(const struct pipe_surface *state,
enum pipe_texture_target target);
void trace_dump_transfer(const struct pipe_transfer *state);
void trace_dump_vertex_buffer(const struct pipe_vertex_buffer *state);
void trace_dump_vertex_element(const struct pipe_vertex_element *state);
void trace_dump_constant_buffer(const struct pipe_constant_buffer *state);
void trace_dump_shader_buffer(const struct pipe_shader_buffer *buffer);
void trace_dump_draw_info(const struct pipe_draw_info *state);
void trace_dump_draw_vertex_state_info(struct pipe_draw_vertex_state_info state);
void trace_dump_draw_start_count(const struct pipe_draw_start_count_bias *state);
void trace_dump_draw_start_count_indexed(const struct pipe_draw_start_count_bias *state);
void trace_dump_draw_indirect_info(const struct pipe_draw_indirect_info *state);
void trace_dump_blit_info(const struct pipe_blit_info *);
void trace_dump_query_result(unsigned query_type, unsigned index,
const union pipe_query_result *result);
void trace_dump_grid_info(const struct pipe_grid_info *state);
void trace_dump_compute_state_object_info(const struct pipe_compute_state_object_info *state);
void trace_dump_image_view(const struct pipe_image_view *view);
void trace_dump_memory_info(const struct pipe_memory_info *state);
void trace_dump_winsys_handle(const struct winsys_handle *whandle);
void trace_dump_vm_allocation(struct pipe_vm_allocation *alloc);
#endif /* TR_STATE_H */
@@ -0,0 +1,50 @@
/**************************************************************************
*
* Copyright 2010 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 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 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
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS 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.
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
**************************************************************************/
#ifndef TR_PUBLIC_H
#define TR_PUBLIC_H
#include "util/compiler.h"
#ifdef __cplusplus
extern "C" {
#endif
struct pipe_screen;
struct pipe_context;
PUBLIC struct pipe_screen *
trace_screen_create(struct pipe_screen *screen);
bool
trace_enabled(void);
#ifdef __cplusplus
}
#endif
#endif /* TR_PUBLIC_H */
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,64 @@
/**************************************************************************
*
* Copyright 2008 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 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 ITS 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 TR_SCREEN_H_
#define TR_SCREEN_H_
#include "pipe/p_screen.h"
#include "util/u_thread.h"
#include "util/u_threaded_context.h"
#ifdef __cplusplus
extern "C" {
#endif
static inline const char *
tr_util_mesa_shader_stage_name(mesa_shader_stage stage)
{
return mesa_shader_stage_name(stage);
}
struct trace_screen
{
struct pipe_screen base;
struct pipe_screen *screen;
tc_is_resource_busy is_resource_busy;
bool trace_tc;
};
struct trace_screen *
trace_screen(struct pipe_screen *screen);
#ifdef __cplusplus
}
#endif
#endif /* TR_SCREEN_H_ */
@@ -0,0 +1,108 @@
/**************************************************************************
*
* Copyright 2008 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 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 ITS 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 "util/u_inlines.h"
#include "util/u_hash_table.h"
#include "util/u_memory.h"
#include "tr_screen.h"
#include "tr_context.h"
#include "tr_texture.h"
struct pipe_transfer *
trace_transfer_create(struct trace_context *tr_ctx,
struct pipe_resource *res,
struct pipe_transfer *transfer)
{
struct trace_transfer *tr_trans;
if (!transfer)
goto error;
tr_trans = CALLOC_STRUCT(trace_transfer);
if (!tr_trans)
goto error;
memcpy(&tr_trans->base, transfer, tr_ctx->threaded ? sizeof(struct threaded_transfer) : sizeof(struct pipe_transfer));
tr_trans->base.b.resource = NULL;
tr_trans->transfer = transfer;
pipe_resource_reference(&tr_trans->base.b.resource, res);
assert(tr_trans->base.b.resource == res);
return &tr_trans->base.b;
error:
if (res->target == PIPE_BUFFER)
tr_ctx->pipe->buffer_unmap(tr_ctx->pipe, transfer);
else
tr_ctx->pipe->texture_unmap(tr_ctx->pipe, transfer);
return NULL;
}
void
trace_transfer_destroy(struct trace_context *tr_context,
struct trace_transfer *tr_trans)
{
pipe_resource_reference(&tr_trans->base.b.resource, NULL);
FREE(tr_trans);
}
struct pipe_sampler_view *
trace_sampler_view_create(struct trace_context *tr_ctx,
struct pipe_resource *tr_res,
struct pipe_sampler_view *view)
{
assert(tr_res == view->texture);
struct trace_sampler_view *tr_view = CALLOC_STRUCT(trace_sampler_view);
memcpy(&tr_view->base, view, sizeof(struct pipe_sampler_view));
tr_view->base.reference.count = 1;
tr_view->base.texture = NULL;
pipe_resource_reference(&tr_view->base.texture, tr_res);
tr_view->base.context = &tr_ctx->base;
tr_view->sampler_view = view;
return &tr_view->base;
}
void
trace_sampler_view_destroy(struct trace_sampler_view *tr_view)
{
pipe_resource_reference(&tr_view->base.texture, NULL);
FREE(tr_view);
}
struct pipe_sampler_view *
trace_sampler_view_unwrap(struct trace_sampler_view *tr_view)
{
if (!tr_view)
return NULL;
return tr_view->sampler_view;
}
#undef SAMPLER_VIEW_PRIVATE_REFCOUNT
@@ -0,0 +1,106 @@
/**************************************************************************
*
* Copyright 2008 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 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 ITS 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 TR_TEXTURE_H_
#define TR_TEXTURE_H_
#include "util/compiler.h"
#include "pipe/p_state.h"
#include "tr_screen.h"
#include "util/u_threaded_context.h"
struct trace_context;
struct tr_list
{
struct tr_list *next;
struct tr_list *prev;
};
struct trace_sampler_view
{
struct pipe_sampler_view base;
unsigned refcount;
struct pipe_sampler_view *sampler_view;
};
struct trace_transfer
{
struct threaded_transfer base;
struct pipe_transfer *transfer;
struct pipe_context *pipe;
struct tr_list list;
void *map;
};
static inline struct trace_sampler_view *
trace_sampler_view(struct pipe_sampler_view *sampler_view)
{
if (!sampler_view)
return NULL;
return (struct trace_sampler_view *)sampler_view;
}
static inline struct trace_transfer *
trace_transfer(struct pipe_transfer *transfer)
{
if (!transfer)
return NULL;
return (struct trace_transfer *)transfer;
}
struct pipe_transfer *
trace_transfer_create(struct trace_context *tr_ctx,
struct pipe_resource *tr_res,
struct pipe_transfer *transfer);
void
trace_transfer_destroy(struct trace_context *tr_ctx,
struct trace_transfer *tr_trans);
struct pipe_sampler_view *
trace_sampler_view_create(struct trace_context *tr_ctx,
struct pipe_resource *tr_res,
struct pipe_sampler_view *sampler_view);
void
trace_sampler_view_destroy(struct trace_sampler_view *tr_view);
struct pipe_sampler_view *
trace_sampler_view_unwrap(struct trace_sampler_view *tr_view);
#endif /* TR_TEXTURE_H_ */
@@ -0,0 +1,478 @@
#include "tr_public.h"
#include "tr_dump.h"
#include "tr_dump_state.h"
#include "tr_texture.h"
#include "u_inlines.h"
#include "u_video.h"
#include "tr_video.h"
#include "pipe/p_video_codec.h"
#include "pipe/p_video_enums.h"
#include "util/macros.h"
#include "util/u_memory.h"
#include "vl/vl_defines.h"
static void
trace_video_codec_destroy(struct pipe_video_codec *_codec)
{
struct trace_video_codec *tr_vcodec = trace_video_codec(_codec);
struct pipe_video_codec *video_codec = tr_vcodec->video_codec;
trace_dump_call_begin("pipe_video_codec", "destroy");
trace_dump_arg(ptr, video_codec);
trace_dump_call_end();
video_codec->destroy(video_codec);
ralloc_free(tr_vcodec);
}
static void
unwrap_refrence_frames_in_place(struct pipe_video_buffer **refrence_frames, unsigned max_num_refrence_frame)
{
for (unsigned i=0; i < max_num_refrence_frame; i++) {
if (refrence_frames[i]) {
struct trace_video_buffer *tr_buffer = trace_video_buffer(refrence_frames[i]);
refrence_frames[i] = tr_buffer->video_buffer;
}
}
}
static bool
unwrap_refrence_frames(struct pipe_picture_desc **picture)
{
// only decode pictures use video buffers for refrences
if ((*picture)->entry_point != PIPE_VIDEO_ENTRYPOINT_BITSTREAM)
return false;
switch (u_reduce_video_profile((*picture)->profile)) {
case PIPE_VIDEO_FORMAT_MPEG12: {
struct pipe_mpeg12_picture_desc *copied = mem_dup(*picture, sizeof(struct pipe_mpeg12_picture_desc));
assert(copied);
unwrap_refrence_frames_in_place(copied->ref, ARRAY_SIZE(copied->ref));
*picture = (struct pipe_picture_desc*)copied;
return true;
}
case PIPE_VIDEO_FORMAT_VC1:{
struct pipe_vc1_picture_desc *copied = mem_dup(*picture, sizeof(struct pipe_vc1_picture_desc));
assert(copied);
unwrap_refrence_frames_in_place(copied->ref, ARRAY_SIZE(copied->ref));
*picture = (struct pipe_picture_desc*)copied;
return true;
}
case PIPE_VIDEO_FORMAT_MPEG4_AVC: {
struct pipe_h264_picture_desc *copied = mem_dup(*picture, sizeof(struct pipe_h264_picture_desc));
assert(copied);
unwrap_refrence_frames_in_place(copied->ref, ARRAY_SIZE(copied->ref));
*picture = (struct pipe_picture_desc*)copied;
return true;
}
case PIPE_VIDEO_FORMAT_HEVC:{
struct pipe_h265_picture_desc *copied = mem_dup(*picture, sizeof(struct pipe_h265_picture_desc));
assert(copied);
unwrap_refrence_frames_in_place(copied->ref, ARRAY_SIZE(copied->ref));
*picture = (struct pipe_picture_desc*)copied;
return true;
}
case PIPE_VIDEO_FORMAT_JPEG:
return false;
case PIPE_VIDEO_FORMAT_VP9:{
struct pipe_vp9_picture_desc *copied = mem_dup(*picture, sizeof(struct pipe_vp9_picture_desc));
assert(copied);
unwrap_refrence_frames_in_place(copied->ref, ARRAY_SIZE(copied->ref));
*picture = (struct pipe_picture_desc*)copied;
return true;
}
case PIPE_VIDEO_FORMAT_AV1:{
struct pipe_av1_picture_desc *copied = mem_dup(*picture, sizeof(struct pipe_av1_picture_desc));
assert(copied);
unwrap_refrence_frames_in_place(copied->ref, ARRAY_SIZE(copied->ref));
unwrap_refrence_frames_in_place(&copied->film_grain_target, 1);
*picture = (struct pipe_picture_desc*)copied;
return true;
}
case PIPE_VIDEO_FORMAT_UNKNOWN:
default:
UNREACHABLE("unknown video format");
}
}
static void
trace_video_codec_begin_frame(struct pipe_video_codec *_codec,
struct pipe_video_buffer *_target,
struct pipe_picture_desc *picture)
{
struct trace_video_codec *tr_vcodec = trace_video_codec(_codec);
struct pipe_video_codec *codec = tr_vcodec->video_codec;
struct trace_video_buffer *tr_target = trace_video_buffer(_target);
struct pipe_video_buffer *target = tr_target->video_buffer;
trace_dump_call_begin("pipe_video_codec", "begin_frame");
trace_dump_arg(ptr, codec);
trace_dump_arg(ptr, target);
trace_dump_arg(pipe_picture_desc, picture);
trace_dump_call_end();
bool copied = unwrap_refrence_frames(&picture);
codec->begin_frame(codec, target, picture);
if (copied)
FREE(picture);
}
static void
trace_video_codec_decode_macroblock(struct pipe_video_codec *_codec,
struct pipe_video_buffer *_target,
struct pipe_picture_desc *picture,
const struct pipe_macroblock *macroblocks,
unsigned num_macroblocks)
{
struct trace_video_codec *tr_vcodec = trace_video_codec(_codec);
struct pipe_video_codec *codec = tr_vcodec->video_codec;
struct trace_video_buffer *tr_target = trace_video_buffer(_target);
struct pipe_video_buffer *target = tr_target->video_buffer;
trace_dump_call_begin("pipe_video_codec", "decode_macroblock");
trace_dump_arg(ptr, codec);
trace_dump_arg(ptr, target);
trace_dump_arg(pipe_picture_desc, picture);
// TODO: how to dump pipe_macroblocks? It's only a single pointer,
// but each struct has codec dependent size, so can't use generic trace_dump_arg_array
trace_dump_arg(ptr, macroblocks);
trace_dump_arg(uint, num_macroblocks);
trace_dump_call_end();
bool copied = unwrap_refrence_frames(&picture);
codec->decode_macroblock(codec, target, picture, macroblocks, num_macroblocks);
if (copied)
FREE(picture);
}
static void
trace_video_codec_decode_bitstream(struct pipe_video_codec *_codec,
struct pipe_video_buffer *_target,
struct pipe_picture_desc *picture,
unsigned num_buffers,
const void * const *buffers,
const unsigned *sizes)
{
struct trace_video_codec *tr_vcodec = trace_video_codec(_codec);
struct pipe_video_codec *codec = tr_vcodec->video_codec;
struct trace_video_buffer *tr_target = trace_video_buffer(_target);
struct pipe_video_buffer *target = tr_target->video_buffer;
trace_dump_call_begin("pipe_video_codec", "decode_bitstream");
trace_dump_arg(ptr, codec);
trace_dump_arg(ptr, target);
trace_dump_arg(pipe_picture_desc, picture);
trace_dump_arg(uint, num_buffers);
trace_dump_arg_array(ptr, buffers, num_buffers);
trace_dump_arg_array(uint, sizes, num_buffers);
trace_dump_call_end();
bool copied = unwrap_refrence_frames(&picture);
codec->decode_bitstream(codec, target, picture, num_buffers, buffers, sizes);
if (copied)
FREE(picture);
}
static void
trace_video_codec_encode_bitstream(struct pipe_video_codec *_codec,
struct pipe_video_buffer *_source,
struct pipe_resource *destination,
void **feedback)
{
struct trace_video_codec *tr_vcodec = trace_video_codec(_codec);
struct pipe_video_codec *codec = tr_vcodec->video_codec;
struct trace_video_buffer *tr_source = trace_video_buffer(_source);
struct pipe_video_buffer *source = tr_source->video_buffer;
trace_dump_call_begin("pipe_video_codec", "encode_bitstream");
trace_dump_arg(ptr, codec);
trace_dump_arg(ptr, source);
trace_dump_arg(ptr, destination);
trace_dump_arg(ptr, feedback);
trace_dump_call_end();
codec->encode_bitstream(codec, source, destination, feedback);
}
static int
trace_video_codec_process_frame(struct pipe_video_codec *_codec,
struct pipe_video_buffer *_source,
const struct pipe_vpp_desc *process_properties)
{
struct trace_video_codec *tr_vcodec = trace_video_codec(_codec);
struct pipe_video_codec *codec = tr_vcodec->video_codec;
struct trace_video_buffer *tr_source = trace_video_buffer(_source);
struct pipe_video_buffer *source = tr_source->video_buffer;
trace_dump_call_begin("pipe_video_codec", "process_frame");
trace_dump_arg(ptr, codec);
trace_dump_arg(ptr, source);
trace_dump_arg(pipe_vpp_desc, process_properties);
trace_dump_call_end();
codec->process_frame(codec, source, process_properties);
return 0;
}
static int
trace_video_codec_end_frame(struct pipe_video_codec *_codec,
struct pipe_video_buffer *_target,
struct pipe_picture_desc *picture)
{
struct trace_video_codec *tr_vcodec = trace_video_codec(_codec);
struct pipe_video_codec *codec = tr_vcodec->video_codec;
struct trace_video_buffer *tr_target = trace_video_buffer(_target);
struct pipe_video_buffer *target = tr_target->video_buffer;
trace_dump_call_begin("pipe_video_codec", "end_frame");
trace_dump_arg(ptr, codec);
trace_dump_arg(ptr, target);
trace_dump_arg(pipe_picture_desc, picture);
trace_dump_call_end();
bool copied = unwrap_refrence_frames(&picture);
codec->end_frame(codec, target, picture);
if (copied)
FREE(picture);
return 0;
}
static void
trace_video_codec_flush(struct pipe_video_codec *_codec)
{
struct trace_video_codec *tr_vcodec = trace_video_codec(_codec);
struct pipe_video_codec *codec = tr_vcodec->video_codec;
trace_dump_call_begin("pipe_video_codec", "flush");
trace_dump_arg(ptr, codec);
trace_dump_call_end();
codec->flush(codec);
}
static void
trace_video_codec_get_feedback(struct pipe_video_codec *_codec,
void *feedback,
unsigned *size,
struct pipe_enc_feedback_metadata* metadata)
{
struct trace_video_codec *tr_vcodec = trace_video_codec(_codec);
struct pipe_video_codec *codec = tr_vcodec->video_codec;
trace_dump_call_begin("pipe_video_codec", "get_feedback");
trace_dump_arg(ptr, codec);
trace_dump_arg(ptr, feedback);
trace_dump_arg(ptr, size);
trace_dump_call_end();
codec->get_feedback(codec, feedback, size, metadata);
}
static int
trace_video_codec_fence_wait(struct pipe_video_codec *_codec,
struct pipe_fence_handle *fence,
uint64_t timeout)
{
struct trace_video_codec *tr_vcodec = trace_video_codec(_codec);
struct pipe_video_codec *codec = tr_vcodec->video_codec;
trace_dump_call_begin("pipe_video_codec", "fence_wait");
trace_dump_arg(ptr, codec);
trace_dump_arg(ptr, fence);
trace_dump_arg(uint, timeout);
int ret = codec->fence_wait(codec, fence, timeout);
trace_dump_ret(int, ret);
trace_dump_call_end();
return ret;
}
struct pipe_video_codec *
trace_video_codec_create(struct trace_context *tr_ctx,
struct pipe_video_codec *video_codec)
{
struct trace_video_codec *tr_vcodec;
if (!video_codec)
goto error1;
if (!trace_enabled())
goto error1;
tr_vcodec = rzalloc(NULL, struct trace_video_codec);
if (!tr_vcodec)
goto error1;
memcpy(&tr_vcodec->base, video_codec, sizeof(struct pipe_video_codec));
tr_vcodec->base.context = &tr_ctx->base;
#define TR_VC_INIT(_member) \
tr_vcodec->base . _member = video_codec -> _member ? trace_video_codec_ ## _member : NULL
TR_VC_INIT(destroy);
TR_VC_INIT(begin_frame);
TR_VC_INIT(decode_macroblock);
TR_VC_INIT(decode_bitstream);
TR_VC_INIT(encode_bitstream);
TR_VC_INIT(process_frame);
TR_VC_INIT(end_frame);
TR_VC_INIT(flush);
TR_VC_INIT(get_feedback);
TR_VC_INIT(fence_wait);
#undef TR_VC_INIT
tr_vcodec->video_codec = video_codec;
return &tr_vcodec->base;
error1:
return video_codec;
}
static void
trace_video_buffer_destroy(struct pipe_video_buffer *_buffer)
{
struct trace_video_buffer *tr_vbuffer = trace_video_buffer(_buffer);
struct pipe_video_buffer *video_buffer = tr_vbuffer->video_buffer;
trace_dump_call_begin("pipe_video_buffer", "destroy");
trace_dump_arg(ptr, video_buffer);
trace_dump_call_end();
for (int i=0; i < VL_NUM_COMPONENTS; i++) {
pipe_sampler_view_reference(&tr_vbuffer->sampler_view_planes[i], NULL);
pipe_sampler_view_reference(&tr_vbuffer->sampler_view_components[i], NULL);
}
video_buffer->destroy(video_buffer);
ralloc_free(tr_vbuffer);
}
static void
trace_video_buffer_get_resources(struct pipe_video_buffer *_buffer, struct pipe_resource **resources)
{
struct trace_video_buffer *tr_vbuffer = trace_video_buffer(_buffer);
struct pipe_video_buffer *buffer = tr_vbuffer->video_buffer;
trace_dump_call_begin("pipe_video_buffer", "get_resources");
trace_dump_arg(ptr, buffer);
buffer->get_resources(buffer, resources);
// TODO: A `trace_dump_ret_arg` style of function would be more appropriate
trace_dump_arg_array(ptr, resources, VL_NUM_COMPONENTS);
trace_dump_call_end();
}
static struct pipe_sampler_view **
trace_video_buffer_get_sampler_view_planes(struct pipe_video_buffer *_buffer)
{
struct trace_context *tr_ctx = trace_context(_buffer->context);
struct trace_video_buffer *tr_vbuffer = trace_video_buffer(_buffer);
struct pipe_video_buffer *buffer = tr_vbuffer->video_buffer;
trace_dump_call_begin("pipe_video_buffer", "get_sampler_view_planes");
trace_dump_arg(ptr, buffer);
struct pipe_sampler_view **view_planes = buffer->get_sampler_view_planes(buffer);
trace_dump_ret_array(ptr, view_planes, VL_NUM_COMPONENTS);
trace_dump_call_end();
for (int i=0; i < VL_NUM_COMPONENTS; i++) {
if (!view_planes || !view_planes[i]) {
pipe_sampler_view_reference(&tr_vbuffer->sampler_view_planes[i], NULL);
} else if (tr_vbuffer->sampler_view_planes[i] == NULL || (trace_sampler_view(tr_vbuffer->sampler_view_planes[i])->sampler_view != view_planes[i])) {
pipe_sampler_view_reference(&tr_vbuffer->sampler_view_planes[i], trace_sampler_view_create(tr_ctx, view_planes[i]->texture, view_planes[i]));
}
}
return view_planes ? tr_vbuffer->sampler_view_planes : NULL;
}
static struct pipe_sampler_view **
trace_video_buffer_get_sampler_view_components(struct pipe_video_buffer *_buffer)
{
struct trace_context *tr_ctx = trace_context(_buffer->context);
struct trace_video_buffer *tr_vbuffer = trace_video_buffer(_buffer);
struct pipe_video_buffer *buffer = tr_vbuffer->video_buffer;
trace_dump_call_begin("pipe_video_buffer", "get_sampler_view_components");
trace_dump_arg(ptr, buffer);
struct pipe_sampler_view **view_components = buffer->get_sampler_view_components(buffer);
trace_dump_ret_array(ptr, view_components, VL_NUM_COMPONENTS);
trace_dump_call_end();
for (int i=0; i < VL_NUM_COMPONENTS; i++) {
if (!view_components || !view_components[i]) {
pipe_sampler_view_reference(&tr_vbuffer->sampler_view_components[i], NULL);
} else if (tr_vbuffer->sampler_view_components[i] == NULL || (trace_sampler_view(tr_vbuffer->sampler_view_components[i])->sampler_view != view_components[i])) {
pipe_sampler_view_reference(&tr_vbuffer->sampler_view_components[i], trace_sampler_view_create(tr_ctx, view_components[i]->texture, view_components[i]));
}
}
return view_components ? tr_vbuffer->sampler_view_components : NULL;
}
static struct pipe_surface *
trace_video_buffer_get_surfaces(struct pipe_video_buffer *_buffer)
{
struct trace_video_buffer *tr_vbuffer = trace_video_buffer(_buffer);
struct pipe_video_buffer *buffer = tr_vbuffer->video_buffer;
trace_dump_call_begin("pipe_video_buffer", "get_surfaces");
trace_dump_arg(ptr, buffer);
struct pipe_surface *surfaces = buffer->get_surfaces(buffer);
trace_dump_array_impl(surface, surfaces, VL_MAX_SURFACES, &);
trace_dump_call_end();
return surfaces;
}
struct pipe_video_buffer *
trace_video_buffer_create(struct trace_context *tr_ctx,
struct pipe_video_buffer *video_buffer)
{
struct trace_video_buffer *tr_vbuffer;
if (!video_buffer)
goto error1;
if (!trace_enabled())
goto error1;
tr_vbuffer = rzalloc(NULL, struct trace_video_buffer);
if (!tr_vbuffer)
goto error1;
memcpy(&tr_vbuffer->base, video_buffer, sizeof(struct pipe_video_buffer));
tr_vbuffer->base.context = &tr_ctx->base;
#define TR_VB_INIT(_member) \
tr_vbuffer->base . _member = video_buffer -> _member ? trace_video_buffer_ ## _member : NULL
TR_VB_INIT(destroy);
TR_VB_INIT(get_resources);
TR_VB_INIT(get_sampler_view_planes);
TR_VB_INIT(get_sampler_view_components);
TR_VB_INIT(get_surfaces);
#undef TR_VB_INIT
tr_vbuffer->video_buffer = video_buffer;
return &tr_vbuffer->base;
error1:
return video_buffer;
}
@@ -0,0 +1,50 @@
#ifndef TR_VIDEO_H_
#define TR_VIDEO_H_
#include "pipe/p_video_codec.h"
#include "vl/vl_defines.h"
#include "tr_context.h"
struct trace_video_codec
{
struct pipe_video_codec base;
struct pipe_video_codec *video_codec;
};
static inline struct trace_video_codec *
trace_video_codec(struct pipe_video_codec *video_codec)
{
assert(video_codec);
return (struct trace_video_codec *)video_codec;
}
struct pipe_video_codec *
trace_video_codec_create(struct trace_context *tr_ctx, struct pipe_video_codec *video_codec);
struct trace_video_buffer
{
struct pipe_video_buffer base;
struct pipe_video_buffer *video_buffer;
struct pipe_sampler_view *sampler_view_planes[VL_NUM_COMPONENTS];
struct pipe_sampler_view *sampler_view_components[VL_NUM_COMPONENTS];
};
static inline struct trace_video_buffer *
trace_video_buffer(struct pipe_video_buffer *video_buffer)
{
assert(video_buffer);
return (struct trace_video_buffer *)video_buffer;
}
struct pipe_video_buffer *
trace_video_buffer_create(struct trace_context *tr_ctx, struct pipe_video_buffer *video_buffer);
#endif /* TR_VIDEO_H_ */
@@ -0,0 +1,196 @@
<?xml version="1.0"?>
<!--
Copyright 2008 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 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 ITS 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.
!-->
<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" />
<xsl:strip-space elements="*" />
<xsl:template match="/trace">
<html>
<head>
<title>Gallium Trace</title>
</head>
<style>
body {
font-family: verdana, sans-serif;
font-size: 11px;
font-weight: normal;
text-align : left;
}
.fun {
font-weight: bold;
}
.var {
font-style: italic;
}
.typ {
display: none;
}
.lit {
color: #0000ff;
}
.ptr {
color: #008000;
}
</style>
<body>
<ol class="calls">
<xsl:apply-templates/>
</ol>
</body>
</html>
</xsl:template>
<xsl:template match="call">
<li>
<xsl:attribute name="value">
<xsl:apply-templates select="@no"/>
</xsl:attribute>
<span class="fun">
<xsl:value-of select="@class"/>
<xsl:text>::</xsl:text>
<xsl:value-of select="@method"/>
</span>
<xsl:text>(</xsl:text>
<xsl:apply-templates select="arg"/>
<xsl:text>)</xsl:text>
<xsl:apply-templates select="ret"/>
</li>
</xsl:template>
<xsl:template match="arg|member">
<xsl:apply-templates select="@name"/>
<xsl:text> = </xsl:text>
<xsl:apply-templates />
<xsl:if test="position() != last()">
<xsl:text>, </xsl:text>
</xsl:if>
</xsl:template>
<xsl:template match="ret">
<xsl:text> = </xsl:text>
<xsl:apply-templates />
</xsl:template>
<xsl:template match="bool|int|uint|float|enum">
<span class="lit">
<xsl:value-of select="text()"/>
</span>
</xsl:template>
<xsl:template match="bytes">
<span class="lit">
<xsl:text>...</xsl:text>
</span>
</xsl:template>
<xsl:template match="string">
<span class="lit">
<xsl:text>"</xsl:text>
<xsl:call-template name="break">
<xsl:with-param name="text" select="text()"/>
</xsl:call-template>
<xsl:text>"</xsl:text>
</span>
</xsl:template>
<xsl:template match="array|struct">
<xsl:text>{</xsl:text>
<xsl:apply-templates />
<xsl:text>}</xsl:text>
</xsl:template>
<xsl:template match="elem">
<xsl:apply-templates />
<xsl:if test="position() != last()">
<xsl:text>, </xsl:text>
</xsl:if>
</xsl:template>
<xsl:template match="null">
<span class="ptr">
<xsl:text>NULL</xsl:text>
</span>
</xsl:template>
<xsl:template match="ptr">
<span class="ptr">
<xsl:value-of select="text()"/>
</span>
</xsl:template>
<xsl:template match="@name">
<span class="var">
<xsl:value-of select="."/>
</span>
</xsl:template>
<xsl:template name="break">
<xsl:param name="text" select="."/>
<xsl:choose>
<xsl:when test="contains($text, '&#xa;')">
<xsl:value-of select="substring-before($text, '&#xa;')"/>
<br/>
<xsl:call-template name="break">
<xsl:with-param name="text" select="substring-after($text, '&#xa;')"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$text"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="replace">
<xsl:param name="text"/>
<xsl:param name="from"/>
<xsl:param name="to"/>
<xsl:choose>
<xsl:when test="contains($text,$from)">
<xsl:value-of select="concat(substring-before($text,$from),$to)"/>
<xsl:call-template name="replace">
<xsl:with-param name="text" select="substring-after($text,$from)"/>
<xsl:with-param name="from" select="$from"/>
<xsl:with-param name="to" select="$to"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$text"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:transform>
+101
View File
@@ -0,0 +1,101 @@
/**************************************************************************
*
* (C) Copyright VMware, Inc 2010.
* (C) Copyright John Maddock 2006.
* Use, modification and distribution are subject to the
* Boost Software License, Version 1.0. (See accompanying file
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*
**************************************************************************/
/*
* This file allows to compute the minimax polynomial coefficients we use
* for fast exp2/log2.
*
* How to use this source:
*
* - Download and build the NTL library from
* http://shoup.net/ntl/download.html , or install libntl-dev package if on
* Debian.
*
* - Download boost source code matching to your distro.
*
* - Goto libs/math/minimax and replace f.cpp with this file.
*
* - Build as
*
* g++ -o minimax -I /path/to/ntl/include main.cpp f.cpp /path/to/ntl/src/ntl.a
*
* - Run as
*
* ./minimax
*
* - For example, to compute exp2 5th order polynomial between [0, 1] do:
*
* variant 0
* range 0 1
* order 5 0
* step 200
* info
*
* and take the coefficients from the P = { ... } array.
*
* - To compute log2 4th order polynomial between [0, 1/9] do:
*
* variant 1
* range 0 0.111111112
* order 4 0
* step 200
* info
*
* - For more info see
* http://www.boost.org/doc/libs/1_47_0/libs/math/doc/sf_and_dist/html/math_toolkit/toolkit/internals2/minimax.html
*/
#define L22
#include <boost/math/bindings/rr.hpp>
#include <boost/math/tools/polynomial.hpp>
#include <cmath>
boost::math::ntl::RR exp2(const boost::math::ntl::RR& x)
{
return exp(x*log(2.0));
}
boost::math::ntl::RR log2(const boost::math::ntl::RR& x)
{
return log(x)/log(2.0);
}
boost::math::ntl::RR f(const boost::math::ntl::RR& x, int variant)
{
switch(variant)
{
case 0:
return exp2(x);
case 1:
return log2((1.0 + sqrt(x))/(1.0 - sqrt(x)))/sqrt(x);
}
return 0;
}
void show_extra(
const boost::math::tools::polynomial<boost::math::ntl::RR>& n,
const boost::math::tools::polynomial<boost::math::ntl::RR>& d,
const boost::math::ntl::RR& x_offset,
const boost::math::ntl::RR& y_offset,
int variant)
{
switch(variant)
{
default:
// do nothing here...
;
}
}
+136
View File
@@ -0,0 +1,136 @@
/**************************************************************************
*
* Copyright 2010 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 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 ITS 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.
*
**************************************************************************/
/**
* @file
* Wrapper for LLVM header file #includes.
*/
#ifndef LP_BLD_H
#define LP_BLD_H
/**
* @file
* LLVM IR building helpers interfaces.
*
* We use LLVM-C bindings for now. They are not documented, but follow the C++
* interfaces very closely, and appear to be complete enough for code
* genration. See
* http://npcontemplation.blogspot.com/2008/06/secret-of-llvm-c-bindings.html
* for a standalone example.
*/
#include <llvm/Config/llvm-config.h>
#include <llvm-c/Core.h>
#if GALLIVM_USE_ORCJIT
#include <llvm-c/Orc.h>
#endif
#include <assert.h>
#include <stdbool.h>
#include <stddef.h>
/**
* Redefine these LLVM entrypoints as invalid macros to make sure we
* don't accidentally use them. We need to use the functions which
* take an explicit LLVMContextRef parameter.
*/
#define LLVMInt1Type ILLEGAL_LLVM_FUNCTION
#define LLVMInt8Type ILLEGAL_LLVM_FUNCTION
#define LLVMInt16Type ILLEGAL_LLVM_FUNCTION
#define LLVMInt32Type ILLEGAL_LLVM_FUNCTION
#define LLVMInt64Type ILLEGAL_LLVM_FUNCTION
#define LLVMIntType ILLEGAL_LLVM_FUNCTION
#define LLVMFloatType ILLEGAL_LLVM_FUNCTION
#define LLVMDoubleType ILLEGAL_LLVM_FUNCTION
#define LLVMX86FP80Type ILLEGAL_LLVM_FUNCTION
#define LLVMFP128Type ILLEGAL_LLVM_FUNCTION
#define LLVMPPCFP128Type ILLEGAL_LLVM_FUNCTION
#define LLVMStructType ILLEGAL_LLVM_FUNCTION
#define LLVMVoidType ILLEGAL_LLVM_FUNCTION
#define LLVMLabelType ILLEGAL_LLVM_FUNCTION
#define LLVMOpaqueType ILLEGAL_LLVM_FUNCTION
#define LLVMUnionType ILLEGAL_LLVM_FUNCTION
#define LLVMMDString ILLEGAL_LLVM_FUNCTION
#define LLVMMDNode ILLEGAL_LLVM_FUNCTION
#define LLVMConstString ILLEGAL_LLVM_FUNCTION
#define LLVMConstStruct ILLEGAL_LLVM_FUNCTION
#define LLVMAppendBasicBlock ILLEGAL_LLVM_FUNCTION
#define LLVMInsertBasicBlock ILLEGAL_LLVM_FUNCTION
#define LLVMCreateBuilder ILLEGAL_LLVM_FUNCTION
typedef struct lp_context_ref {
LLVMContextRef ref;
#if GALLIVM_USE_ORCJIT
LLVMOrcThreadSafeContextRef tsref;
#endif
bool owned;
} lp_context_ref;
static inline void
lp_context_create(lp_context_ref *context)
{
assert(context != NULL);
#if GALLIVM_USE_ORCJIT
#if LLVM_VERSION_MAJOR >= 21
context->ref = LLVMContextCreate();
/* Ownership of ref is then transferred to tsref */
context->tsref = LLVMOrcCreateNewThreadSafeContextFromLLVMContext(context->ref);
#else
context->tsref = LLVMOrcCreateNewThreadSafeContext();
context->ref = LLVMOrcThreadSafeContextGetContext(context->tsref);
#endif
#else
context->ref = LLVMContextCreate();
#endif
context->owned = true;
#if LLVM_VERSION_MAJOR == 15
if (context->ref) {
LLVMContextSetOpaquePointers(context->ref, false);
}
#endif
}
static inline void
lp_context_destroy(lp_context_ref *context)
{
assert(context != NULL);
if (context->owned) {
#if GALLIVM_USE_ORCJIT
LLVMOrcDisposeThreadSafeContext(context->tsref);
#else
LLVMContextDispose(context->ref);
#endif
context->ref = NULL;
}
}
#endif /* LP_BLD_H */
Loaded 100 of 12511 files, more files were not shown because too many files have changed in this diff. Show more