mirror of
https://github.com/elwrcl/intel-hard-graphics.git
synced 2026-11-02 03:28:02 +03:00
init
This commit is contained in:
12511 files changed
+6156641
No files matched your search
@@ -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.
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
|
||||
@@ -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
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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"
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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"
|
||||
@@ -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 */
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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"
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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"
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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_*/
|
||||
@@ -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");
|
||||
}
|
||||
@@ -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
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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("<");
|
||||
else if(c == '>')
|
||||
trace_dump_writes(">");
|
||||
else if(c == '&')
|
||||
trace_dump_writes("&");
|
||||
else if(c == '\'')
|
||||
trace_dump_writes("'");
|
||||
else if(c == '\"')
|
||||
trace_dump_writes(""");
|
||||
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, '
')">
|
||||
<xsl:value-of select="substring-before($text, '
')"/>
|
||||
<br/>
|
||||
<xsl:call-template name="break">
|
||||
<xsl:with-param name="text" select="substring-after($text, '
')"/>
|
||||
</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>
|
||||
@@ -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...
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
Reference in new issue
Block a user