aboutsummaryrefslogtreecommitdiffstats
path: root/src/gallium/drivers
diff options
context:
space:
mode:
authorDave Airlie <[email protected]>2020-02-17 17:15:38 +1000
committerDave Airlie <[email protected]>2020-02-28 18:33:34 +1000
commiteb5227173f0354aade28e46397a5bb69b2af69fb (patch)
tree58a84f35af115b5d6591b93841391841cff426e2 /src/gallium/drivers
parenta3257ae7bec68d57e79928eb202cd522d708e720 (diff)
llvmpipe: add support for tessellation shaders
This adds the hooks between llvmpipe and draw to enable tessellation shaders. It also updates the CI results and docs. Reviewed-by: Roland Scheidegger <[email protected]> Tested-by: Marge Bot <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/3841> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/3841>
Diffstat (limited to 'src/gallium/drivers')
-rw-r--r--src/gallium/drivers/llvmpipe/Makefile.sources1
-rw-r--r--src/gallium/drivers/llvmpipe/lp_context.c1
-rw-r--r--src/gallium/drivers/llvmpipe/lp_context.h2
-rw-r--r--src/gallium/drivers/llvmpipe/lp_draw_arrays.c12
-rw-r--r--src/gallium/drivers/llvmpipe/lp_screen.c10
-rw-r--r--src/gallium/drivers/llvmpipe/lp_state.h39
-rw-r--r--src/gallium/drivers/llvmpipe/lp_state_derived.c2
-rw-r--r--src/gallium/drivers/llvmpipe/lp_state_fs.c12
-rw-r--r--src/gallium/drivers/llvmpipe/lp_state_sampler.c54
-rw-r--r--src/gallium/drivers/llvmpipe/lp_state_tess.c196
-rw-r--r--src/gallium/drivers/llvmpipe/lp_surface.c2
-rw-r--r--src/gallium/drivers/llvmpipe/meson.build1
12 files changed, 324 insertions, 8 deletions
diff --git a/src/gallium/drivers/llvmpipe/Makefile.sources b/src/gallium/drivers/llvmpipe/Makefile.sources
index 9b2fe288346..71579cd02bb 100644
--- a/src/gallium/drivers/llvmpipe/Makefile.sources
+++ b/src/gallium/drivers/llvmpipe/Makefile.sources
@@ -65,6 +65,7 @@ C_SOURCES := \
lp_state_setup.h \
lp_state_so.c \
lp_state_surface.c \
+ lp_state_tess.c \
lp_state_vertex.c \
lp_state_vs.c \
lp_surface.c \
diff --git a/src/gallium/drivers/llvmpipe/lp_context.c b/src/gallium/drivers/llvmpipe/lp_context.c
index c49e6691495..a9c6ae6f11d 100644
--- a/src/gallium/drivers/llvmpipe/lp_context.c
+++ b/src/gallium/drivers/llvmpipe/lp_context.c
@@ -176,6 +176,7 @@ llvmpipe_create_context(struct pipe_screen *screen, void *priv,
llvmpipe_init_fs_funcs(llvmpipe);
llvmpipe_init_vs_funcs(llvmpipe);
llvmpipe_init_gs_funcs(llvmpipe);
+ llvmpipe_init_tess_funcs(llvmpipe);
llvmpipe_init_rasterizer_funcs(llvmpipe);
llvmpipe_init_context_resource_funcs( &llvmpipe->pipe );
llvmpipe_init_surface_functions(llvmpipe);
diff --git a/src/gallium/drivers/llvmpipe/lp_context.h b/src/gallium/drivers/llvmpipe/lp_context.h
index b9bdfa10978..825fde9a7cd 100644
--- a/src/gallium/drivers/llvmpipe/lp_context.h
+++ b/src/gallium/drivers/llvmpipe/lp_context.h
@@ -67,6 +67,8 @@ struct llvmpipe_context {
struct lp_fragment_shader *fs;
struct draw_vertex_shader *vs;
const struct lp_geometry_shader *gs;
+ const struct lp_tess_ctrl_shader *tcs;
+ const struct lp_tess_eval_shader *tes;
struct lp_compute_shader *cs;
const struct lp_velems_state *velems;
const struct lp_so_state *so;
diff --git a/src/gallium/drivers/llvmpipe/lp_draw_arrays.c b/src/gallium/drivers/llvmpipe/lp_draw_arrays.c
index cf81111b407..d9700cfd6d7 100644
--- a/src/gallium/drivers/llvmpipe/lp_draw_arrays.c
+++ b/src/gallium/drivers/llvmpipe/lp_draw_arrays.c
@@ -105,6 +105,12 @@ llvmpipe_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info)
llvmpipe_prepare_geometry_sampling(lp,
lp->num_sampler_views[PIPE_SHADER_GEOMETRY],
lp->sampler_views[PIPE_SHADER_GEOMETRY]);
+ llvmpipe_prepare_tess_ctrl_sampling(lp,
+ lp->num_sampler_views[PIPE_SHADER_TESS_CTRL],
+ lp->sampler_views[PIPE_SHADER_TESS_CTRL]);
+ llvmpipe_prepare_tess_eval_sampling(lp,
+ lp->num_sampler_views[PIPE_SHADER_TESS_EVAL],
+ lp->sampler_views[PIPE_SHADER_TESS_EVAL]);
llvmpipe_prepare_vertex_images(lp,
lp->num_images[PIPE_SHADER_VERTEX],
@@ -112,6 +118,12 @@ llvmpipe_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info)
llvmpipe_prepare_geometry_images(lp,
lp->num_images[PIPE_SHADER_GEOMETRY],
lp->images[PIPE_SHADER_GEOMETRY]);
+ llvmpipe_prepare_tess_ctrl_images(lp,
+ lp->num_images[PIPE_SHADER_TESS_CTRL],
+ lp->images[PIPE_SHADER_TESS_CTRL]);
+ llvmpipe_prepare_tess_eval_images(lp,
+ lp->num_images[PIPE_SHADER_TESS_EVAL],
+ lp->images[PIPE_SHADER_TESS_EVAL]);
if (lp->gs && lp->gs->no_tokens) {
/* we have an empty geometry shader with stream output, so
attach the stream output info to the current vertex shader */
diff --git a/src/gallium/drivers/llvmpipe/lp_screen.c b/src/gallium/drivers/llvmpipe/lp_screen.c
index d0002df5f79..0a8362e16c4 100644
--- a/src/gallium/drivers/llvmpipe/lp_screen.c
+++ b/src/gallium/drivers/llvmpipe/lp_screen.c
@@ -332,10 +332,11 @@ llvmpipe_get_param(struct pipe_screen *screen, enum pipe_cap param)
case PIPE_CAP_MULTI_DRAW_INDIRECT:
case PIPE_CAP_MULTI_DRAW_INDIRECT_PARAMS:
return 1;
+ case PIPE_CAP_MAX_SHADER_PATCH_VARYINGS:
+ return 32;
case PIPE_CAP_MULTISAMPLE_Z_RESOLVE:
case PIPE_CAP_RESOURCE_FROM_USER_MEMORY:
case PIPE_CAP_DEVICE_RESET_STATUS_QUERY:
- case PIPE_CAP_MAX_SHADER_PATCH_VARYINGS:
case PIPE_CAP_DEPTH_BOUNDS_TEST:
case PIPE_CAP_TGSI_TXQS:
case PIPE_CAP_FORCE_PERSAMPLE_INTERP:
@@ -413,6 +414,7 @@ llvmpipe_get_shader_param(struct pipe_screen *screen,
enum pipe_shader_type shader,
enum pipe_shader_cap param)
{
+ struct llvmpipe_screen *lscreen = llvmpipe_screen(screen);
switch(shader)
{
case PIPE_SHADER_COMPUTE:
@@ -420,7 +422,6 @@ llvmpipe_get_shader_param(struct pipe_screen *screen,
return (1 << PIPE_SHADER_IR_TGSI) | (1 << PIPE_SHADER_IR_NIR) | (1 << PIPE_SHADER_IR_NIR_SERIALIZED);
case PIPE_SHADER_FRAGMENT:
if (param == PIPE_SHADER_CAP_PREFERRED_IR) {
- struct llvmpipe_screen *lscreen = llvmpipe_screen(screen);
if (lscreen->use_tgsi)
return PIPE_SHADER_IR_TGSI;
else
@@ -430,10 +431,13 @@ llvmpipe_get_shader_param(struct pipe_screen *screen,
default:
return gallivm_get_shader_param(param);
}
+ case PIPE_SHADER_TESS_CTRL:
+ case PIPE_SHADER_TESS_EVAL:
+ if (lscreen->use_tgsi)
+ return 0;
case PIPE_SHADER_VERTEX:
case PIPE_SHADER_GEOMETRY:
if (param == PIPE_SHADER_CAP_PREFERRED_IR) {
- struct llvmpipe_screen *lscreen = llvmpipe_screen(screen);
if (lscreen->use_tgsi)
return PIPE_SHADER_IR_TGSI;
else
diff --git a/src/gallium/drivers/llvmpipe/lp_state.h b/src/gallium/drivers/llvmpipe/lp_state.h
index a14ed06f711..f695f006399 100644
--- a/src/gallium/drivers/llvmpipe/lp_state.h
+++ b/src/gallium/drivers/llvmpipe/lp_state.h
@@ -58,6 +58,8 @@
#define LP_NEW_SO_BUFFERS 0x40000
#define LP_NEW_FS_SSBOS 0x80000
#define LP_NEW_FS_IMAGES 0x100000
+#define LP_NEW_TCS 0x200000
+#define LP_NEW_TES 0x400000
#define LP_CSNEW_CS 0x1
#define LP_CSNEW_CONSTANTS 0x2
@@ -78,6 +80,19 @@ struct lp_geometry_shader {
struct draw_geometry_shader *dgs;
};
+struct lp_tess_ctrl_shader {
+ boolean no_tokens;
+ struct pipe_stream_output_info stream_output;
+ struct draw_tess_ctrl_shader *dtcs;
+};
+
+struct lp_tess_eval_shader {
+ boolean no_tokens;
+ struct pipe_stream_output_info stream_output;
+ struct draw_tess_eval_shader *dtes;
+};
+
+
/** Vertex element state */
struct lp_velems_state
{
@@ -131,6 +146,9 @@ void
llvmpipe_init_gs_funcs(struct llvmpipe_context *llvmpipe);
void
+llvmpipe_init_tess_funcs(struct llvmpipe_context *llvmpipe);
+
+void
llvmpipe_init_rasterizer_funcs(struct llvmpipe_context *llvmpipe);
void
@@ -147,6 +165,16 @@ llvmpipe_prepare_geometry_sampling(struct llvmpipe_context *ctx,
struct pipe_sampler_view **views);
void
+llvmpipe_prepare_tess_ctrl_sampling(struct llvmpipe_context *ctx,
+ unsigned num,
+ struct pipe_sampler_view **views);
+
+void
+llvmpipe_prepare_tess_eval_sampling(struct llvmpipe_context *ctx,
+ unsigned num,
+ struct pipe_sampler_view **views);
+
+void
llvmpipe_prepare_vertex_images(struct llvmpipe_context *lp,
unsigned num,
struct pipe_image_view *views);
@@ -155,4 +183,15 @@ void
llvmpipe_prepare_geometry_images(struct llvmpipe_context *lp,
unsigned num,
struct pipe_image_view *views);
+
+void
+llvmpipe_prepare_tess_ctrl_images(struct llvmpipe_context *lp,
+ unsigned num,
+ struct pipe_image_view *views);
+
+void
+llvmpipe_prepare_tess_eval_images(struct llvmpipe_context *lp,
+ unsigned num,
+ struct pipe_image_view *views);
+
#endif
diff --git a/src/gallium/drivers/llvmpipe/lp_state_derived.c b/src/gallium/drivers/llvmpipe/lp_state_derived.c
index 6f8e855e8ae..9fe0ddf1fb2 100644
--- a/src/gallium/drivers/llvmpipe/lp_state_derived.c
+++ b/src/gallium/drivers/llvmpipe/lp_state_derived.c
@@ -195,6 +195,8 @@ void llvmpipe_update_derived( struct llvmpipe_context *llvmpipe )
if (llvmpipe->dirty & (LP_NEW_RASTERIZER |
LP_NEW_FS |
LP_NEW_GS |
+ LP_NEW_TCS |
+ LP_NEW_TES |
LP_NEW_VS))
compute_vertex_info(llvmpipe);
diff --git a/src/gallium/drivers/llvmpipe/lp_state_fs.c b/src/gallium/drivers/llvmpipe/lp_state_fs.c
index 846cdd69ae9..cb1627849d0 100644
--- a/src/gallium/drivers/llvmpipe/lp_state_fs.c
+++ b/src/gallium/drivers/llvmpipe/lp_state_fs.c
@@ -3167,7 +3167,9 @@ llvmpipe_set_constant_buffer(struct pipe_context *pipe,
}
if (shader == PIPE_SHADER_VERTEX ||
- shader == PIPE_SHADER_GEOMETRY) {
+ shader == PIPE_SHADER_GEOMETRY ||
+ shader == PIPE_SHADER_TESS_CTRL ||
+ shader == PIPE_SHADER_TESS_EVAL) {
/* Pass the constants to the 'draw' module */
const unsigned size = cb ? cb->buffer_size : 0;
const ubyte *data;
@@ -3212,7 +3214,9 @@ llvmpipe_set_shader_buffers(struct pipe_context *pipe,
util_copy_shader_buffer(&llvmpipe->ssbos[shader][i], buffer);
if (shader == PIPE_SHADER_VERTEX ||
- shader == PIPE_SHADER_GEOMETRY) {
+ shader == PIPE_SHADER_GEOMETRY ||
+ shader == PIPE_SHADER_TESS_CTRL ||
+ shader == PIPE_SHADER_TESS_EVAL) {
const unsigned size = buffer ? buffer->buffer_size : 0;
const ubyte *data = NULL;
if (buffer && buffer->buffer)
@@ -3246,7 +3250,9 @@ llvmpipe_set_shader_images(struct pipe_context *pipe,
llvmpipe->num_images[shader] = start_slot + count;
if (shader == PIPE_SHADER_VERTEX ||
- shader == PIPE_SHADER_GEOMETRY) {
+ shader == PIPE_SHADER_GEOMETRY ||
+ shader == PIPE_SHADER_TESS_CTRL ||
+ shader == PIPE_SHADER_TESS_EVAL) {
draw_set_images(llvmpipe->draw,
shader,
llvmpipe->images[shader],
diff --git a/src/gallium/drivers/llvmpipe/lp_state_sampler.c b/src/gallium/drivers/llvmpipe/lp_state_sampler.c
index 0428b5cd2c5..485822df63b 100644
--- a/src/gallium/drivers/llvmpipe/lp_state_sampler.c
+++ b/src/gallium/drivers/llvmpipe/lp_state_sampler.c
@@ -92,7 +92,10 @@ llvmpipe_bind_sampler_states(struct pipe_context *pipe,
llvmpipe->num_samplers[shader] = j;
}
- if (shader == PIPE_SHADER_VERTEX || shader == PIPE_SHADER_GEOMETRY) {
+ if (shader == PIPE_SHADER_VERTEX ||
+ shader == PIPE_SHADER_GEOMETRY ||
+ shader == PIPE_SHADER_TESS_CTRL ||
+ shader == PIPE_SHADER_TESS_EVAL) {
draw_set_samplers(llvmpipe->draw,
shader,
llvmpipe->samplers[shader],
@@ -146,7 +149,10 @@ llvmpipe_set_sampler_views(struct pipe_context *pipe,
llvmpipe->num_sampler_views[shader] = j;
}
- if (shader == PIPE_SHADER_VERTEX || shader == PIPE_SHADER_GEOMETRY) {
+ if (shader == PIPE_SHADER_VERTEX ||
+ shader == PIPE_SHADER_GEOMETRY ||
+ shader == PIPE_SHADER_TESS_CTRL ||
+ shader == PIPE_SHADER_TESS_EVAL) {
draw_set_sampler_views(llvmpipe->draw,
shader,
llvmpipe->sampler_views[shader],
@@ -360,6 +366,28 @@ llvmpipe_prepare_geometry_sampling(struct llvmpipe_context *lp,
prepare_shader_sampling(lp, num, views, PIPE_SHADER_GEOMETRY);
}
+/**
+ * Called whenever we're about to draw (no dirty flag, FIXME?).
+ */
+void
+llvmpipe_prepare_tess_ctrl_sampling(struct llvmpipe_context *lp,
+ unsigned num,
+ struct pipe_sampler_view **views)
+{
+ prepare_shader_sampling(lp, num, views, PIPE_SHADER_TESS_CTRL);
+}
+
+/**
+ * Called whenever we're about to draw (no dirty flag, FIXME?).
+ */
+void
+llvmpipe_prepare_tess_eval_sampling(struct llvmpipe_context *lp,
+ unsigned num,
+ struct pipe_sampler_view **views)
+{
+ prepare_shader_sampling(lp, num, views, PIPE_SHADER_TESS_EVAL);
+}
+
static void
prepare_shader_images(
struct llvmpipe_context *lp,
@@ -472,6 +500,28 @@ llvmpipe_prepare_geometry_images(struct llvmpipe_context *lp,
prepare_shader_images(lp, num, views, PIPE_SHADER_GEOMETRY);
}
+/**
+ * Called whenever we're about to draw (no dirty flag, FIXME?).
+ */
+void
+llvmpipe_prepare_tess_ctrl_images(struct llvmpipe_context *lp,
+ unsigned num,
+ struct pipe_image_view *views)
+{
+ prepare_shader_images(lp, num, views, PIPE_SHADER_TESS_CTRL);
+}
+
+/**
+ * Called whenever we're about to draw (no dirty flag, FIXME?).
+ */
+void
+llvmpipe_prepare_tess_eval_images(struct llvmpipe_context *lp,
+ unsigned num,
+ struct pipe_image_view *views)
+{
+ prepare_shader_images(lp, num, views, PIPE_SHADER_TESS_EVAL);
+}
+
void
llvmpipe_init_sampler_funcs(struct llvmpipe_context *llvmpipe)
{
diff --git a/src/gallium/drivers/llvmpipe/lp_state_tess.c b/src/gallium/drivers/llvmpipe/lp_state_tess.c
new file mode 100644
index 00000000000..b3f8e74af97
--- /dev/null
+++ b/src/gallium/drivers/llvmpipe/lp_state_tess.c
@@ -0,0 +1,196 @@
+/**************************************************************************
+ *
+ * Copyright 2019 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 "lp_context.h"
+#include "lp_state.h"
+#include "lp_texture.h"
+#include "lp_debug.h"
+
+#include "pipe/p_defines.h"
+#include "util/u_memory.h"
+#include "util/u_inlines.h"
+#include "draw/draw_context.h"
+#include "tgsi/tgsi_dump.h"
+#include "tgsi/tgsi_scan.h"
+#include "tgsi/tgsi_parse.h"
+
+
+static void *
+llvmpipe_create_tcs_state(struct pipe_context *pipe,
+ const struct pipe_shader_state *templ)
+{
+ struct llvmpipe_context *llvmpipe = llvmpipe_context(pipe);
+ struct lp_tess_ctrl_shader *state;
+
+ state = CALLOC_STRUCT(lp_tess_ctrl_shader);
+ if (!state)
+ goto no_state;
+
+ /* debug */
+ if (LP_DEBUG & DEBUG_TGSI) {
+ debug_printf("llvmpipe: Create tess ctrl shader %p:\n", (void *)state);
+ tgsi_dump(templ->tokens, 0);
+ }
+
+ /* copy stream output info */
+ state->no_tokens = !templ->tokens;
+ memcpy(&state->stream_output, &templ->stream_output, sizeof state->stream_output);
+
+ if (templ->tokens || templ->type == PIPE_SHADER_IR_NIR) {
+ state->dtcs = draw_create_tess_ctrl_shader(llvmpipe->draw, templ);
+ if (state->dtcs == NULL) {
+ goto no_dgs;
+ }
+ }
+
+ return state;
+
+no_dgs:
+ FREE( state );
+no_state:
+ return NULL;
+}
+
+
+static void
+llvmpipe_bind_tcs_state(struct pipe_context *pipe, void *tcs)
+{
+ struct llvmpipe_context *llvmpipe = llvmpipe_context(pipe);
+
+ llvmpipe->tcs = (struct lp_tess_ctrl_shader *)tcs;
+
+ draw_bind_tess_ctrl_shader(llvmpipe->draw,
+ (llvmpipe->tcs ? llvmpipe->tcs->dtcs : NULL));
+
+ llvmpipe->dirty |= LP_NEW_TCS;
+}
+
+
+static void
+llvmpipe_delete_tcs_state(struct pipe_context *pipe, void *tcs)
+{
+ struct llvmpipe_context *llvmpipe = llvmpipe_context(pipe);
+
+ struct lp_tess_ctrl_shader *state =
+ (struct lp_tess_ctrl_shader *)tcs;
+
+ if (!state) {
+ return;
+ }
+
+ draw_delete_tess_ctrl_shader(llvmpipe->draw, state->dtcs);
+ FREE(state);
+}
+
+
+static void *
+llvmpipe_create_tes_state(struct pipe_context *pipe,
+ const struct pipe_shader_state *templ)
+{
+ struct llvmpipe_context *llvmpipe = llvmpipe_context(pipe);
+ struct lp_tess_eval_shader *state;
+
+ state = CALLOC_STRUCT(lp_tess_eval_shader);
+ if (!state)
+ goto no_state;
+
+ /* debug */
+ if (LP_DEBUG & DEBUG_TGSI) {
+ debug_printf("llvmpipe: Create tess eval shader %p:\n", (void *)state);
+ tgsi_dump(templ->tokens, 0);
+ }
+
+ /* copy stream output info */
+ state->no_tokens = !templ->tokens;
+ memcpy(&state->stream_output, &templ->stream_output, sizeof state->stream_output);
+
+ if (templ->tokens || templ->type == PIPE_SHADER_IR_NIR) {
+ state->dtes = draw_create_tess_eval_shader(llvmpipe->draw, templ);
+ if (state->dtes == NULL) {
+ goto no_dgs;
+ }
+ }
+
+ return state;
+
+no_dgs:
+ FREE( state );
+no_state:
+ return NULL;
+}
+
+
+static void
+llvmpipe_bind_tes_state(struct pipe_context *pipe, void *tes)
+{
+ struct llvmpipe_context *llvmpipe = llvmpipe_context(pipe);
+
+ llvmpipe->tes = (struct lp_tess_eval_shader *)tes;
+
+ draw_bind_tess_eval_shader(llvmpipe->draw,
+ (llvmpipe->tes ? llvmpipe->tes->dtes : NULL));
+
+ llvmpipe->dirty |= LP_NEW_TES;
+}
+
+
+static void
+llvmpipe_delete_tes_state(struct pipe_context *pipe, void *tes)
+{
+ struct llvmpipe_context *llvmpipe = llvmpipe_context(pipe);
+
+ struct lp_tess_eval_shader *state =
+ (struct lp_tess_eval_shader *)tes;
+
+ if (!state) {
+ return;
+ }
+
+ draw_delete_tess_eval_shader(llvmpipe->draw, state->dtes);
+ FREE(state);
+}
+
+static void
+llvmpipe_set_tess_state(struct pipe_context *pipe,
+ const float default_outer_level[4],
+ const float default_inner_level[2])
+{
+ struct llvmpipe_context *llvmpipe = llvmpipe_context(pipe);
+ draw_set_tess_state(llvmpipe->draw, default_outer_level, default_inner_level);
+}
+
+void
+llvmpipe_init_tess_funcs(struct llvmpipe_context *llvmpipe)
+{
+ llvmpipe->pipe.create_tcs_state = llvmpipe_create_tcs_state;
+ llvmpipe->pipe.bind_tcs_state = llvmpipe_bind_tcs_state;
+ llvmpipe->pipe.delete_tcs_state = llvmpipe_delete_tcs_state;
+
+ llvmpipe->pipe.create_tes_state = llvmpipe_create_tes_state;
+ llvmpipe->pipe.bind_tes_state = llvmpipe_bind_tes_state;
+ llvmpipe->pipe.delete_tes_state = llvmpipe_delete_tes_state;
+
+ llvmpipe->pipe.set_tess_state = llvmpipe_set_tess_state;
+}
diff --git a/src/gallium/drivers/llvmpipe/lp_surface.c b/src/gallium/drivers/llvmpipe/lp_surface.c
index 953b26e8cdb..1cdabbb6cc3 100644
--- a/src/gallium/drivers/llvmpipe/lp_surface.c
+++ b/src/gallium/drivers/llvmpipe/lp_surface.c
@@ -102,6 +102,8 @@ static void lp_blit(struct pipe_context *pipe,
util_blitter_save_scissor(lp->blitter, &lp->scissors[0]);
util_blitter_save_fragment_shader(lp->blitter, lp->fs);
util_blitter_save_blend(lp->blitter, (void*)lp->blend);
+ util_blitter_save_tessctrl_shader(lp->blitter, (void*)lp->tcs);
+ util_blitter_save_tesseval_shader(lp->blitter, (void*)lp->tes);
util_blitter_save_depth_stencil_alpha(lp->blitter, (void*)lp->depth_stencil);
util_blitter_save_stencil_ref(lp->blitter, &lp->stencil_ref);
/*util_blitter_save_sample_mask(sp->blitter, lp->sample_mask);*/
diff --git a/src/gallium/drivers/llvmpipe/meson.build b/src/gallium/drivers/llvmpipe/meson.build
index d2577418e5d..138c2ce871b 100644
--- a/src/gallium/drivers/llvmpipe/meson.build
+++ b/src/gallium/drivers/llvmpipe/meson.build
@@ -85,6 +85,7 @@ files_llvmpipe = files(
'lp_state_setup.h',
'lp_state_so.c',
'lp_state_surface.c',
+ 'lp_state_tess.c',
'lp_state_vertex.c',
'lp_state_vs.c',
'lp_surface.c',