summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/gallium/auxiliary/util/u_surface.c71
-rw-r--r--src/gallium/auxiliary/util/u_surface.h19
-rw-r--r--src/gallium/drivers/llvmpipe/Makefile12
-rw-r--r--src/gallium/drivers/llvmpipe/SConscript16
-rw-r--r--src/gallium/drivers/llvmpipe/lp_bld_arit.c2
-rw-r--r--src/gallium/drivers/llvmpipe/lp_bld_conv.c4
-rw-r--r--src/gallium/drivers/llvmpipe/lp_bld_flow.c308
-rw-r--r--src/gallium/drivers/llvmpipe/lp_bld_flow.h27
-rw-r--r--src/gallium/drivers/llvmpipe/lp_bld_interp.c135
-rw-r--r--src/gallium/drivers/llvmpipe/lp_bld_interp.h10
-rw-r--r--src/gallium/drivers/llvmpipe/lp_bld_logic.c86
-rw-r--r--src/gallium/drivers/llvmpipe/lp_bld_logic.h8
-rw-r--r--src/gallium/drivers/llvmpipe/lp_bld_type.c21
-rw-r--r--src/gallium/drivers/llvmpipe/lp_bld_type.h4
-rw-r--r--src/gallium/drivers/llvmpipe/lp_buffer.c31
-rw-r--r--src/gallium/drivers/llvmpipe/lp_clear.c38
-rw-r--r--src/gallium/drivers/llvmpipe/lp_context.c112
-rw-r--r--src/gallium/drivers/llvmpipe/lp_context.h39
-rw-r--r--src/gallium/drivers/llvmpipe/lp_draw_arrays.c8
-rw-r--r--src/gallium/drivers/llvmpipe/lp_fence.c109
-rw-r--r--src/gallium/drivers/llvmpipe/lp_fence.h60
-rw-r--r--src/gallium/drivers/llvmpipe/lp_flush.c54
-rw-r--r--src/gallium/drivers/llvmpipe/lp_jit.h12
-rw-r--r--src/gallium/drivers/llvmpipe/lp_prim_vbuf.c563
-rw-r--r--src/gallium/drivers/llvmpipe/lp_quad.h114
-rw-r--r--src/gallium/drivers/llvmpipe/lp_rast.c793
-rw-r--r--src/gallium/drivers/llvmpipe/lp_rast.h238
-rw-r--r--src/gallium/drivers/llvmpipe/lp_rast_priv.h129
-rw-r--r--src/gallium/drivers/llvmpipe/lp_rast_tri.c253
-rw-r--r--src/gallium/drivers/llvmpipe/lp_scene.c310
-rw-r--r--src/gallium/drivers/llvmpipe/lp_scene.h276
-rw-r--r--src/gallium/drivers/llvmpipe/lp_scene_queue.c164
-rw-r--r--src/gallium/drivers/llvmpipe/lp_scene_queue.h55
-rw-r--r--src/gallium/drivers/llvmpipe/lp_screen.c2
-rw-r--r--src/gallium/drivers/llvmpipe/lp_setup.c1722
-rw-r--r--src/gallium/drivers/llvmpipe/lp_setup.h107
-rw-r--r--src/gallium/drivers/llvmpipe/lp_setup_context.h146
-rw-r--r--src/gallium/drivers/llvmpipe/lp_setup_line.c (renamed from src/gallium/drivers/llvmpipe/lp_tile_cache.h)62
-rw-r--r--src/gallium/drivers/llvmpipe/lp_setup_point.c (renamed from src/gallium/drivers/llvmpipe/lp_prim_vbuf.h)30
-rw-r--r--src/gallium/drivers/llvmpipe/lp_setup_tri.c547
-rw-r--r--src/gallium/drivers/llvmpipe/lp_setup_vbuf.c520
-rw-r--r--src/gallium/drivers/llvmpipe/lp_state.h14
-rw-r--r--src/gallium/drivers/llvmpipe/lp_state_blend.c18
-rw-r--r--src/gallium/drivers/llvmpipe/lp_state_derived.c190
-rw-r--r--src/gallium/drivers/llvmpipe/lp_state_fs.c170
-rw-r--r--src/gallium/drivers/llvmpipe/lp_state_rasterizer.c11
-rw-r--r--src/gallium/drivers/llvmpipe/lp_state_sampler.c13
-rw-r--r--src/gallium/drivers/llvmpipe/lp_state_surface.c52
-rw-r--r--src/gallium/drivers/llvmpipe/lp_tex_cache.c304
-rw-r--r--src/gallium/drivers/llvmpipe/lp_tex_cache.h151
-rw-r--r--src/gallium/drivers/llvmpipe/lp_tex_sample_llvm.c2
-rw-r--r--src/gallium/drivers/llvmpipe/lp_texture.c4
-rw-r--r--src/gallium/drivers/llvmpipe/lp_tile_cache.c358
-rw-r--r--src/gallium/drivers/llvmpipe/lp_tile_soa.h19
-rw-r--r--src/gallium/drivers/llvmpipe/lp_tile_soa.py6
-rw-r--r--src/gallium/include/pipe/p_thread.h151
56 files changed, 5263 insertions, 3417 deletions
diff --git a/src/gallium/auxiliary/util/u_surface.c b/src/gallium/auxiliary/util/u_surface.c
index 35c4978204..f66376ad75 100644
--- a/src/gallium/auxiliary/util/u_surface.c
+++ b/src/gallium/auxiliary/util/u_surface.c
@@ -36,6 +36,7 @@
#include "pipe/p_state.h"
#include "pipe/p_defines.h"
+#include "util/u_memory.h"
#include "util/u_format.h"
#include "util/u_surface.h"
@@ -111,3 +112,73 @@ util_destroy_rgba_surface(struct pipe_texture *texture,
pipe_texture_reference(&texture, NULL);
}
+
+
+/**
+ * Compare pipe_framebuffer_state objects.
+ * \return TRUE if same, FALSE if different
+ */
+boolean
+util_framebuffer_state_equal(const struct pipe_framebuffer_state *dst,
+ const struct pipe_framebuffer_state *src)
+{
+ unsigned i;
+
+ if (dst->width != src->width ||
+ dst->height != src->height)
+ return FALSE;
+
+ for (i = 0; i < Elements(src->cbufs); i++) {
+ if (dst->cbufs[i] != src->cbufs[i]) {
+ return FALSE;
+ }
+ }
+
+ if (dst->nr_cbufs != src->nr_cbufs) {
+ return FALSE;
+ }
+
+ if (dst->zsbuf != src->zsbuf) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/**
+ * Copy framebuffer state from src to dst, updating refcounts.
+ */
+void
+util_copy_framebuffer_state(struct pipe_framebuffer_state *dst,
+ const struct pipe_framebuffer_state *src)
+{
+ unsigned i;
+
+ dst->width = src->width;
+ dst->height = src->height;
+
+ for (i = 0; i < Elements(src->cbufs); i++) {
+ pipe_surface_reference(&dst->cbufs[i], src->cbufs[i]);
+ }
+
+ dst->nr_cbufs = src->nr_cbufs;
+
+ pipe_surface_reference(&dst->zsbuf, src->zsbuf);
+}
+
+
+void
+util_unreference_framebuffer_state(struct pipe_framebuffer_state *fb)
+{
+ unsigned i;
+
+ for (i = 0; i < fb->nr_cbufs; i++) {
+ pipe_surface_reference(&fb->cbufs[i], NULL);
+ }
+
+ pipe_surface_reference(&fb->zsbuf, NULL);
+
+ fb->width = fb->height = 0;
+ fb->nr_cbufs = 0;
+}
diff --git a/src/gallium/auxiliary/util/u_surface.h b/src/gallium/auxiliary/util/u_surface.h
index ce84ed7ad0..3c60df2c3e 100644
--- a/src/gallium/auxiliary/util/u_surface.h
+++ b/src/gallium/auxiliary/util/u_surface.h
@@ -30,11 +30,7 @@
#include "pipe/p_compiler.h"
-
-
-struct pipe_screen;
-struct pipe_texture;
-struct pipe_surface;
+#include "pipe/p_state.h"
/**
@@ -66,4 +62,17 @@ util_destroy_rgba_surface(struct pipe_texture *texture,
struct pipe_surface *surface);
+extern boolean
+util_framebuffer_state_equal(const struct pipe_framebuffer_state *dst,
+ const struct pipe_framebuffer_state *src);
+
+extern void
+util_copy_framebuffer_state(struct pipe_framebuffer_state *dst,
+ const struct pipe_framebuffer_state *src);
+
+
+extern void
+util_unreference_framebuffer_state(struct pipe_framebuffer_state *fb);
+
+
#endif /* U_SURFACE_H */
diff --git a/src/gallium/drivers/llvmpipe/Makefile b/src/gallium/drivers/llvmpipe/Makefile
index 7c6e46006b..264999a7ce 100644
--- a/src/gallium/drivers/llvmpipe/Makefile
+++ b/src/gallium/drivers/llvmpipe/Makefile
@@ -6,6 +6,8 @@ LIBNAME = llvmpipe
CFLAGS += -D__STDC_CONSTANT_MACROS -D__STDC_LIMIT_MACROS
C_SOURCES = \
+ lp_scene.c \
+ lp_scene_queue.c \
lp_bld_alpha.c \
lp_bld_arit.c \
lp_bld_blend_aos.c \
@@ -33,10 +35,16 @@ C_SOURCES = \
lp_clear.c \
lp_context.c \
lp_draw_arrays.c \
+ lp_fence.c \
lp_flush.c \
lp_jit.c \
- lp_prim_vbuf.c \
+ lp_rast.c \
+ lp_rast_tri.c \
lp_setup.c \
+ lp_setup_line.c \
+ lp_setup_point.c \
+ lp_setup_tri.c \
+ lp_setup_vbuf.c \
lp_query.c \
lp_screen.c \
lp_state_blend.c \
@@ -49,10 +57,8 @@ C_SOURCES = \
lp_state_vertex.c \
lp_state_vs.c \
lp_surface.c \
- lp_tex_cache.c \
lp_tex_sample_llvm.c \
lp_texture.c \
- lp_tile_cache.c \
lp_tile_soa.c
CPP_SOURCES = \
diff --git a/src/gallium/drivers/llvmpipe/SConscript b/src/gallium/drivers/llvmpipe/SConscript
index 6bb545a501..5af77c4a12 100644
--- a/src/gallium/drivers/llvmpipe/SConscript
+++ b/src/gallium/drivers/llvmpipe/SConscript
@@ -36,12 +36,12 @@ llvmpipe = env.ConvenienceLibrary(
'lp_bld_format_soa.c',
'lp_bld_interp.c',
'lp_bld_intr.c',
+ 'lp_bld_logic.c',
'lp_bld_misc.cpp',
'lp_bld_pack.c',
'lp_bld_sample.c',
'lp_bld_sample_soa.c',
'lp_bld_struct.c',
- 'lp_bld_logic.c',
'lp_bld_swizzle.c',
'lp_bld_tgsi_soa.c',
'lp_bld_type.c',
@@ -49,12 +49,18 @@ llvmpipe = env.ConvenienceLibrary(
'lp_clear.c',
'lp_context.c',
'lp_draw_arrays.c',
+ 'lp_fence.c',
'lp_flush.c',
'lp_jit.c',
- 'lp_prim_vbuf.c',
- 'lp_setup.c',
'lp_query.c',
+ 'lp_scene.c',
+ 'lp_scene_queue.c',
'lp_screen.c',
+ 'lp_setup.c',
+ 'lp_setup_line.c',
+ 'lp_setup_point.c',
+ 'lp_setup_tri.c',
+ 'lp_setup_vbuf.c',
'lp_state_blend.c',
'lp_state_clip.c',
'lp_state_derived.c',
@@ -65,10 +71,10 @@ llvmpipe = env.ConvenienceLibrary(
'lp_state_vertex.c',
'lp_state_vs.c',
'lp_surface.c',
- 'lp_tex_cache.c',
+ 'lp_rast.c',
+ 'lp_rast_tri.c',
'lp_tex_sample_llvm.c',
'lp_texture.c',
- 'lp_tile_cache.c',
'lp_tile_soa.c',
])
diff --git a/src/gallium/drivers/llvmpipe/lp_bld_arit.c b/src/gallium/drivers/llvmpipe/lp_bld_arit.c
index eea6b5d6a5..2df86dd32e 100644
--- a/src/gallium/drivers/llvmpipe/lp_bld_arit.c
+++ b/src/gallium/drivers/llvmpipe/lp_bld_arit.c
@@ -629,7 +629,7 @@ lp_build_abs(struct lp_build_context *bld,
if(type.floating) {
/* Mask out the sign bit */
LLVMTypeRef int_vec_type = lp_build_int_vec_type(type);
- unsigned long absMask = ~(1 << (type.width - 1));
+ unsigned long long absMask = ~(1ULL << (type.width - 1));
LLVMValueRef mask = lp_build_int_const_scalar(type, ((unsigned long long) absMask));
a = LLVMBuildBitCast(bld->builder, a, int_vec_type, "");
a = LLVMBuildAnd(bld->builder, a, mask, "");
diff --git a/src/gallium/drivers/llvmpipe/lp_bld_conv.c b/src/gallium/drivers/llvmpipe/lp_bld_conv.c
index 9935209437..9fa8837202 100644
--- a/src/gallium/drivers/llvmpipe/lp_bld_conv.c
+++ b/src/gallium/drivers/llvmpipe/lp_bld_conv.c
@@ -125,6 +125,10 @@ lp_build_clamped_float_to_unsigned_norm(LLVMBuilderRef builder,
res = LLVMBuildShl(builder, res, lp_build_int_const_scalar(src_type, shift), "");
/* TODO: Fill in the empty lower bits for additional precision? */
+ /* YES: this fixes progs/trivial/tri-z-eq.c.
+ * Otherwise vertex Z=1.0 values get converted to something like
+ * 0xfffffb00 and the test for equality with 0xffffffff fails.
+ */
#if 0
{
LLVMValueRef msb;
diff --git a/src/gallium/drivers/llvmpipe/lp_bld_flow.c b/src/gallium/drivers/llvmpipe/lp_bld_flow.c
index 25c10af29f..230edc6a5c 100644
--- a/src/gallium/drivers/llvmpipe/lp_bld_flow.c
+++ b/src/gallium/drivers/llvmpipe/lp_bld_flow.c
@@ -41,13 +41,16 @@
#define LP_BUILD_FLOW_MAX_VARIABLES 32
#define LP_BUILD_FLOW_MAX_DEPTH 32
+#define LP_BUILD_IF_MAX_VARIABLES 8
+
/**
* Enumeration of all possible flow constructs.
*/
enum lp_build_flow_construct_kind {
- lP_BUILD_FLOW_SCOPE,
- LP_BUILD_FLOW_SKIP
+ LP_BUILD_FLOW_SCOPE,
+ LP_BUILD_FLOW_SKIP,
+ LP_BUILD_FLOW_IF
};
@@ -73,7 +76,24 @@ struct lp_build_flow_skip
/** Number of variables declared at the beginning */
unsigned num_variables;
- LLVMValueRef *phi;
+ LLVMValueRef *phi; /**< array [num_variables] */
+};
+
+
+/**
+ * if/else/endif.
+ */
+struct lp_build_flow_if
+{
+ unsigned num_variables;
+
+ /** phi variables in the true clause */
+ LLVMValueRef true_variables[LP_BUILD_IF_MAX_VARIABLES];
+ unsigned num_true_variables;
+
+ /** phi variables in the false clause */
+ LLVMValueRef false_variables[LP_BUILD_IF_MAX_VARIABLES];
+ unsigned num_false_variables;
};
@@ -84,6 +104,7 @@ union lp_build_flow_construct_data
{
struct lp_build_flow_scope scope;
struct lp_build_flow_skip skip;
+ struct lp_build_flow_if ifthen;
};
@@ -145,6 +166,10 @@ lp_build_flow_destroy(struct lp_build_flow_context *flow)
}
+/**
+ * Begin/push a new flow control construct, such as a loop, skip block
+ * or variable scope.
+ */
static union lp_build_flow_construct_data *
lp_build_flow_push(struct lp_build_flow_context *flow,
enum lp_build_flow_construct_kind kind)
@@ -158,6 +183,10 @@ lp_build_flow_push(struct lp_build_flow_context *flow,
}
+/**
+ * Return the current/top flow control construct on the stack.
+ * \param kind the expected type of the top-most construct
+ */
static union lp_build_flow_construct_data *
lp_build_flow_peek(struct lp_build_flow_context *flow,
enum lp_build_flow_construct_kind kind)
@@ -174,6 +203,10 @@ lp_build_flow_peek(struct lp_build_flow_context *flow,
}
+/**
+ * End/pop the current/top flow control construct on the stack.
+ * \param kind the expected type of the top-most construct
+ */
static union lp_build_flow_construct_data *
lp_build_flow_pop(struct lp_build_flow_context *flow,
enum lp_build_flow_construct_kind kind)
@@ -200,7 +233,7 @@ lp_build_flow_scope_begin(struct lp_build_flow_context *flow)
{
struct lp_build_flow_scope *scope;
- scope = &lp_build_flow_push(flow, lP_BUILD_FLOW_SCOPE)->scope;
+ scope = &lp_build_flow_push(flow, LP_BUILD_FLOW_SCOPE)->scope;
if(!scope)
return;
@@ -213,11 +246,11 @@ lp_build_flow_scope_begin(struct lp_build_flow_context *flow)
*
* A variable is a named entity which can have different LLVMValueRef's at
* different points of the program. This is relevant for control flow because
- * when there are mutiple branches to a same location we need to replace
+ * when there are multiple branches to a same location we need to replace
* the variable's value with a Phi function as explained in
* http://en.wikipedia.org/wiki/Static_single_assignment_form .
*
- * We keep track of variables by keeping around a pointer to where their
+ * We keep track of variables by keeping around a pointer to where they're
* current.
*
* There are a few cautions to observe:
@@ -241,7 +274,7 @@ lp_build_flow_scope_declare(struct lp_build_flow_context *flow,
{
struct lp_build_flow_scope *scope;
- scope = &lp_build_flow_peek(flow, lP_BUILD_FLOW_SCOPE)->scope;
+ scope = &lp_build_flow_peek(flow, LP_BUILD_FLOW_SCOPE)->scope;
if(!scope)
return;
@@ -263,7 +296,7 @@ lp_build_flow_scope_end(struct lp_build_flow_context *flow)
{
struct lp_build_flow_scope *scope;
- scope = &lp_build_flow_pop(flow, lP_BUILD_FLOW_SCOPE)->scope;
+ scope = &lp_build_flow_pop(flow, LP_BUILD_FLOW_SCOPE)->scope;
if(!scope)
return;
@@ -298,6 +331,11 @@ lp_build_flow_insert_block(struct lp_build_flow_context *flow)
return new_block;
}
+
+/**
+ * Begin a "skip" block. Inside this block we can test a condition and
+ * skip to the end of the block if the condition is false.
+ */
void
lp_build_flow_skip_begin(struct lp_build_flow_context *flow)
{
@@ -309,13 +347,16 @@ lp_build_flow_skip_begin(struct lp_build_flow_context *flow)
if(!skip)
return;
+ /* create new basic block */
skip->block = lp_build_flow_insert_block(flow);
+
skip->num_variables = flow->num_variables;
if(!skip->num_variables) {
skip->phi = NULL;
return;
}
+ /* Allocate a Phi node for each variable in this skip scope */
skip->phi = MALLOC(skip->num_variables * sizeof *skip->phi);
if(!skip->phi) {
skip->num_variables = 0;
@@ -325,6 +366,7 @@ lp_build_flow_skip_begin(struct lp_build_flow_context *flow)
builder = LLVMCreateBuilder();
LLVMPositionBuilderAtEnd(builder, skip->block);
+ /* create a Phi node for each variable */
for(i = 0; i < skip->num_variables; ++i)
skip->phi[i] = LLVMBuildPhi(builder, LLVMTypeOf(*flow->variables[i]), "");
@@ -332,6 +374,10 @@ lp_build_flow_skip_begin(struct lp_build_flow_context *flow)
}
+/**
+ * Insert code to test a condition and branch to the end of the current
+ * skip block if the condition is true.
+ */
void
lp_build_flow_skip_cond_break(struct lp_build_flow_context *flow,
LLVMValueRef cond)
@@ -349,15 +395,17 @@ lp_build_flow_skip_cond_break(struct lp_build_flow_context *flow,
new_block = lp_build_flow_insert_block(flow);
+ /* for each variable, update the Phi node with a (variable, block) pair */
for(i = 0; i < skip->num_variables; ++i) {
assert(*flow->variables[i]);
LLVMAddIncoming(skip->phi[i], flow->variables[i], &current_block, 1);
}
+ /* if cond is true, goto skip->block, else goto new_block */
LLVMBuildCondBr(flow->builder, cond, skip->block, new_block);
LLVMPositionBuilderAtEnd(flow->builder, new_block);
- }
+}
void
@@ -373,12 +421,14 @@ lp_build_flow_skip_end(struct lp_build_flow_context *flow)
current_block = LLVMGetInsertBlock(flow->builder);
+ /* add (variable, block) tuples to the phi nodes */
for(i = 0; i < skip->num_variables; ++i) {
assert(*flow->variables[i]);
LLVMAddIncoming(skip->phi[i], flow->variables[i], &current_block, 1);
*flow->variables[i] = skip->phi[i];
}
+ /* goto block */
LLVMBuildBr(flow->builder, skip->block);
LLVMPositionBuilderAtEnd(flow->builder, skip->block);
@@ -386,22 +436,34 @@ lp_build_flow_skip_end(struct lp_build_flow_context *flow)
}
+/**
+ * Check if the mask predicate is zero. If so, jump to the end of the block.
+ */
static void
lp_build_mask_check(struct lp_build_mask_context *mask)
{
LLVMBuilderRef builder = mask->flow->builder;
LLVMValueRef cond;
+ /* cond = (mask == 0) */
cond = LLVMBuildICmp(builder,
LLVMIntEQ,
LLVMBuildBitCast(builder, mask->value, mask->reg_type, ""),
LLVMConstNull(mask->reg_type),
"");
+ /* if cond, goto end of block */
lp_build_flow_skip_cond_break(mask->flow, cond);
}
+/**
+ * Begin a section of code which is predicated on a mask.
+ * \param mask the mask context, initialized here
+ * \param flow the flow context
+ * \param type the type of the mask
+ * \param value storage for the mask
+ */
void
lp_build_mask_begin(struct lp_build_mask_context *mask,
struct lp_build_flow_context *flow,
@@ -422,6 +484,11 @@ lp_build_mask_begin(struct lp_build_mask_context *mask,
}
+/**
+ * Update boolean mask with given value (bitwise AND).
+ * Typically used to update the quad's pixel alive/killed mask
+ * after depth testing, alpha testing, TGSI_OPCODE_KIL, etc.
+ */
void
lp_build_mask_update(struct lp_build_mask_context *mask,
LLVMValueRef value)
@@ -432,6 +499,9 @@ lp_build_mask_update(struct lp_build_mask_context *mask,
}
+/**
+ * End section of code which is predicated on a mask.
+ */
LLVMValueRef
lp_build_mask_end(struct lp_build_mask_context *mask)
{
@@ -491,3 +561,223 @@ lp_build_loop_end(LLVMBuilderRef builder,
LLVMPositionBuilderAtEnd(builder, after_block);
}
+
+
+/*
+ Example of if/then/else building:
+
+ int x;
+ if (cond) {
+ x = 1 + 2;
+ }
+ else {
+ x = 2 + 3;
+ }
+
+ Is built with:
+
+ flow = lp_build_flow_create(builder);
+ ...
+
+ lp_build_flow_scope_declare(flow, "x");
+
+ lp_build_if(ctx, flow, builder, cond);
+ x = LLVMAdd(1, 2);
+ lp_build_if_phi_var(ctx, "x");
+ lp_build_else(ctx);
+ x = LLVMAdd(2, 3);
+ lp_build_if_phi_var(ctx, "x");
+ lp_build_endif(ctx);
+
+ ...
+
+ flow = lp_build_flow_end(flow);
+ */
+
+
+
+/**
+ * Begin an if/else/endif construct.
+ */
+void
+lp_build_if(struct lp_build_if_state *ctx,
+ struct lp_build_flow_context *flow,
+ LLVMBuilderRef builder,
+ LLVMValueRef condition)
+{
+ LLVMBasicBlockRef block = LLVMGetInsertBlock(builder);
+ LLVMValueRef function = LLVMGetBasicBlockParent(block);
+ struct lp_build_flow_if *ifthen;
+
+ memset(ctx, 0, sizeof(*ctx));
+ ctx->builder = builder;
+ ctx->flow = flow;
+ ctx->condition = condition;
+ ctx->entry_block = block;
+
+ /* push/create new scope */
+ ifthen = &lp_build_flow_push(flow, LP_BUILD_FLOW_IF)->ifthen;
+ assert(ifthen);
+
+ ifthen->num_variables = flow->num_variables;
+ ifthen->num_true_variables = 0;
+ ifthen->num_false_variables = 0;
+
+ /* allocate the block for the if/true clause */
+ ctx->true_block = LLVMAppendBasicBlock(function, "true block");
+ /* XXX is this correct ??? */
+ LLVMPositionBuilderAtEnd(builder, ctx->true_block);
+}
+
+
+/**
+ * Begin else-part of a conditional
+ */
+void
+lp_build_else(struct lp_build_if_state *ctx)
+{
+ LLVMBasicBlockRef block = LLVMGetInsertBlock(ctx->builder);
+ LLVMValueRef function = LLVMGetBasicBlockParent(block);
+ struct lp_build_flow_if *ifthen;
+
+ ifthen = &lp_build_flow_peek(ctx->flow, LP_BUILD_FLOW_IF)->ifthen;
+ assert(ifthen);
+
+ /* allocate the block for the else/false clause */
+ ctx->false_block = LLVMAppendBasicBlock(function, "false block");
+ /* XXX is this correct ??? */
+ LLVMPositionBuilderAtEnd(ctx->builder, ctx->false_block);
+}
+
+
+/**
+ * End a conditional.
+ * This involves building a "merge" block at the endif which
+ * contains the phi instructions.
+ */
+void
+lp_build_endif(struct lp_build_if_state *ctx)
+{
+ LLVMBasicBlockRef block = LLVMGetInsertBlock(ctx->builder);
+ LLVMValueRef function = LLVMGetBasicBlockParent(block);
+ LLVMBasicBlockRef merge_block = LLVMAppendBasicBlock(function, "endif block");
+ LLVMValueRef phi[LP_BUILD_FLOW_MAX_VARIABLES];
+ struct lp_build_flow_if *ifthen;
+ unsigned i;
+
+ /* build the endif/merge block now */
+ /* XXX this is probably wrong */
+ LLVMPositionBuilderAtEnd(ctx->builder, merge_block);
+
+ ifthen = &lp_build_flow_pop(ctx->flow, LP_BUILD_FLOW_IF)->ifthen;
+ assert(ifthen);
+
+ memset(phi, 0, sizeof(phi));
+
+ /* build phi nodes for any variables which were declared inside if part */
+
+ for (i = 0; i < ifthen->num_variables; i++) {
+ LLVMValueRef *var = ctx->flow->variables[i];
+ const char *name = LLVMGetValueName(*var);
+ unsigned j;
+
+ /* search true-clause variables list for 'name' */
+ for (j = 0; j < ifthen->num_true_variables; j++) {
+ LLVMValueRef v = ifthen->true_variables[j];
+ if (strcmp(LLVMGetValueName(v), name) == 0) {
+ /* add phi */
+ if (!phi[i])
+ phi[i] = LLVMBuildPhi(ctx->builder, LLVMTypeOf(*var), "");
+ LLVMAddIncoming(phi[i], &v, &ctx->true_block, 1);
+ }
+ }
+
+ /* search false-clause variables list for 'name' */
+ for (j = 0; j < ifthen->num_false_variables; j++) {
+ LLVMValueRef v = ifthen->false_variables[j];
+ if (strcmp(LLVMGetValueName(v), name) == 0) {
+ /* add phi */
+ if (!phi[i])
+ phi[i] = LLVMBuildPhi(ctx->builder, LLVMTypeOf(*var), "");
+ LLVMAddIncoming(phi[i], &v, &ctx->false_block, 1);
+ }
+ }
+
+ /* "return" new phi variable to calling code */
+ if (phi[i])
+ *var = phi[i];
+ }
+
+ /***
+ *** Insert the various branch instructions here.
+ *** XXX need to verify all the builder/block positioning is correct.
+ ***/
+
+ /* Insert the conditional branch instruction at the end of entry_block */
+ LLVMPositionBuilderAtEnd(ctx->builder, ctx->entry_block);
+
+ if (ctx->false_block) {
+ /* we have an else clause */
+ LLVMBuildCondBr(ctx->builder, ctx->condition,
+ ctx->true_block, ctx->false_block);
+ }
+ else {
+ /* no else clause */
+ LLVMBuildCondBr(ctx->builder, ctx->condition,
+ ctx->true_block, merge_block);
+ }
+
+ /* Append an unconditional Br(anch) instruction on the true_block */
+ LLVMPositionBuilderAtEnd(ctx->builder, ctx->true_block);
+ LLVMBuildBr(ctx->builder, merge_block);
+ if (ctx->false_block) {
+ /* Append an unconditional Br(anch) instruction on the false_block */
+ LLVMPositionBuilderAtEnd(ctx->builder, ctx->false_block);
+ LLVMBuildBr(ctx->builder, merge_block);
+ }
+
+
+ /* Finish-up: continue building at end of the merge_block */
+ /* XXX is this right? */
+ LLVMPositionBuilderAtEnd(ctx->builder, merge_block);
+}
+
+
+/**
+ * Declare a variable that needs to be merged with another variable
+ * via a phi function.
+ * This function must be called after lp_build_if() and lp_build_endif().
+ */
+void
+lp_build_if_phi_var(struct lp_build_if_state *ctx, LLVMValueRef var)
+{
+ struct lp_build_flow_if *ifthen;
+ const char *name;
+
+ name = LLVMGetValueName(var);
+ assert(name && "variable requires a name");
+
+ /* make sure the var existed before the if/then/else */
+ {
+ boolean found = FALSE;
+ uint i;
+ for (i = 0; i < ctx->flow->num_variables; i++) {
+ LLVMValueRef *var = ctx->flow->variables[i];
+ if (strcmp(LLVMGetValueName(*var), name) == 0) {
+ found = TRUE;
+ break;
+ }
+ }
+ assert(found);
+ }
+
+ ifthen = &lp_build_flow_pop(ctx->flow, LP_BUILD_FLOW_IF)->ifthen;
+
+ if (ctx->false_block) {
+ ifthen->false_variables[ifthen->num_false_variables++] = var;
+ }
+ else {
+ assert(ctx->true_block);
+ ifthen->true_variables[ifthen->num_true_variables++] = var;
+ }
+}
diff --git a/src/gallium/drivers/llvmpipe/lp_bld_flow.h b/src/gallium/drivers/llvmpipe/lp_bld_flow.h
index e61999ff06..1f294b8a49 100644
--- a/src/gallium/drivers/llvmpipe/lp_bld_flow.h
+++ b/src/gallium/drivers/llvmpipe/lp_bld_flow.h
@@ -126,4 +126,31 @@ lp_build_loop_end(LLVMBuilderRef builder,
+
+struct lp_build_if_state
+{
+ LLVMBuilderRef builder;
+ struct lp_build_flow_context *flow;
+ LLVMValueRef condition;
+ LLVMBasicBlockRef entry_block, true_block, false_block;
+};
+
+
+void
+lp_build_if(struct lp_build_if_state *ctx,
+ struct lp_build_flow_context *flow,
+ LLVMBuilderRef builder,
+ LLVMValueRef condition);
+
+void
+lp_build_if_phi_var(struct lp_build_if_state *ctx, LLVMValueRef var);
+
+void
+lp_build_else(struct lp_build_if_state *ctx);
+
+void
+lp_build_endif(struct lp_build_if_state *ctx);
+
+
+
#endif /* !LP_BLD_FLOW_H */
diff --git a/src/gallium/drivers/llvmpipe/lp_bld_interp.c b/src/gallium/drivers/llvmpipe/lp_bld_interp.c
index 49dab8ab61..daedf40d55 100644
--- a/src/gallium/drivers/llvmpipe/lp_bld_interp.c
+++ b/src/gallium/drivers/llvmpipe/lp_bld_interp.c
@@ -45,6 +45,36 @@
#include "lp_bld_interp.h"
+/*
+ * The shader JIT function operates on blocks of quads.
+ * Each block has 2x2 quads and each quad has 2x2 pixels.
+ *
+ * We iterate over the quads in order 0, 1, 2, 3:
+ *
+ * #################
+ * # | # | #
+ * #---0---#---1---#
+ * # | # | #
+ * #################
+ * # | # | #
+ * #---2---#---3---#
+ * # | # | #
+ * #################
+ *
+ * Within each quad, we have four pixels which are represented in SOA
+ * order:
+ *
+ * #########
+ * # 0 | 1 #
+ * #---+---#
+ * # 2 | 3 #
+ * #########
+ *
+ * So the green channel (for example) of the four pixels is stored in
+ * a single vector register: {g0, g1, g2, g3}.
+ */
+
+
static void
attrib_name(LLVMValueRef val, unsigned attrib, unsigned chan, const char *suffix)
{
@@ -55,6 +85,10 @@ attrib_name(LLVMValueRef val, unsigned attrib, unsigned chan, const char *suffix
}
+/**
+ * Initialize the bld->a0, dadx, dady fields. This involves fetching
+ * those values from the arrays which are passed into the JIT function.
+ */
static void
coeffs_init(struct lp_build_interp_soa_context *bld,
LLVMValueRef a0_ptr,
@@ -91,7 +125,7 @@ coeffs_init(struct lp_build_interp_soa_context *bld,
case TGSI_INTERPOLATE_CONSTANT:
a0 = LLVMBuildLoad(builder, LLVMBuildGEP(builder, a0_ptr, &index, 1, ""), "");
a0 = lp_build_broadcast_scalar(&bld->base, a0);
- attrib_name(a0, attrib, chan, ".dady");
+ attrib_name(a0, attrib, chan, ".a0");
break;
default:
@@ -109,30 +143,13 @@ coeffs_init(struct lp_build_interp_soa_context *bld,
/**
- * Multiply the dadx and dady with the xstep and ystep respectively.
+ * Emit LLVM code to compute the fragment shader input attribute values.
+ * For example, for a color input, we'll compute red, green, blue and alpha
+ * values for the four pixels in a quad.
+ * Recall that we're operating on 4-element vectors so each arithmetic
+ * operation is operating on the four pixels in a quad.
*/
static void
-coeffs_update(struct lp_build_interp_soa_context *bld)
-{
- unsigned attrib;
- unsigned chan;
-
- for(attrib = 0; attrib < bld->num_attribs; ++attrib) {
- unsigned mask = bld->mask[attrib];
- unsigned mode = bld->mode[attrib];
- if (mode != TGSI_INTERPOLATE_CONSTANT) {
- for(chan = 0; chan < NUM_CHANNELS; ++chan) {
- if(mask & (1 << chan)) {
- bld->dadx[attrib][chan] = lp_build_mul_imm(&bld->base, bld->dadx[attrib][chan], bld->xstep);
- bld->dady[attrib][chan] = lp_build_mul_imm(&bld->base, bld->dady[attrib][chan], bld->ystep);
- }
- }
- }
- }
-}
-
-
-static void
attribs_init(struct lp_build_interp_soa_context *bld)
{
LLVMValueRef x = bld->pos[0];
@@ -154,7 +171,9 @@ attribs_init(struct lp_build_interp_soa_context *bld)
res = a0;
if (mode != TGSI_INTERPOLATE_CONSTANT) {
+ /* res = res + x * dadx */
res = lp_build_add(&bld->base, res, lp_build_mul(&bld->base, x, dadx));
+ /* res = res + y * dady */
res = lp_build_add(&bld->base, res, lp_build_mul(&bld->base, y, dady));
}
@@ -178,13 +197,19 @@ attribs_init(struct lp_build_interp_soa_context *bld)
}
+/**
+ * Increment the shader input attribute values.
+ * This is called when we move from one quad to the next.
+ */
static void
-attribs_update(struct lp_build_interp_soa_context *bld)
+attribs_update(struct lp_build_interp_soa_context *bld, int quad_index)
{
LLVMValueRef oow = NULL;
unsigned attrib;
unsigned chan;
+ assert(quad_index < 4);
+
for(attrib = 0; attrib < bld->num_attribs; ++attrib) {
unsigned mask = bld->mask[attrib];
unsigned mode = bld->mode[attrib];
@@ -198,13 +223,21 @@ attribs_update(struct lp_build_interp_soa_context *bld)
res = bld->attribs_pre[attrib][chan];
- if(bld->xstep)
+ if (quad_index == 1 || quad_index == 3) {
+ /* top-right or bottom-right quad */
+ /* build res = res + dadx + dadx */
res = lp_build_add(&bld->base, res, dadx);
+ res = lp_build_add(&bld->base, res, dadx);
+ }
- if(bld->ystep)
+ if (quad_index == 2 || quad_index == 3) {
+ /* bottom-left or bottom-right quad */
+ /* build res = res + dady + dady */
res = lp_build_add(&bld->base, res, dady);
+ res = lp_build_add(&bld->base, res, dady);
+ }
- bld->attribs_pre[attrib][chan] = res;
+ //XXX bld->attribs_pre[attrib][chan] = res;
if (mode == TGSI_INTERPOLATE_PERSPECTIVE) {
LLVMValueRef w = bld->pos[3];
@@ -242,17 +275,32 @@ pos_init(struct lp_build_interp_soa_context *bld,
}
+/**
+ * Update quad position values when moving to the next quad.
+ */
static void
-pos_update(struct lp_build_interp_soa_context *bld)
+pos_update(struct lp_build_interp_soa_context *bld, int quad_index)
{
LLVMValueRef x = bld->attribs[0][0];
LLVMValueRef y = bld->attribs[0][1];
+ const int xstep = 2, ystep = 2;
- if(bld->xstep)
- x = lp_build_add(&bld->base, x, lp_build_const_scalar(bld->base.type, bld->xstep));
+ if (quad_index == 1 || quad_index == 3) {
+ /* top-right or bottom-right quad in block */
+ /* build x += xstep */
+ x = lp_build_add(&bld->base, x,
+ lp_build_const_scalar(bld->base.type, xstep));
+ }
- if(bld->ystep)
- y = lp_build_add(&bld->base, y, lp_build_const_scalar(bld->base.type, bld->ystep));
+ if (quad_index == 2) {
+ /* bottom-left quad in block */
+ /* build y += ystep */
+ y = lp_build_add(&bld->base, y,
+ lp_build_const_scalar(bld->base.type, ystep));
+ /* build x -= xstep */
+ x = lp_build_sub(&bld->base, x,
+ lp_build_const_scalar(bld->base.type, xstep));
+ }
lp_build_name(x, "pos.x");
lp_build_name(y, "pos.y");
@@ -262,6 +310,9 @@ pos_update(struct lp_build_interp_soa_context *bld)
}
+/**
+ * Initialize fragment shader input attribute info.
+ */
void
lp_build_interp_soa_init(struct lp_build_interp_soa_context *bld,
const struct tgsi_token *tokens,
@@ -271,9 +322,7 @@ lp_build_interp_soa_init(struct lp_build_interp_soa_context *bld,
LLVMValueRef dadx_ptr,
LLVMValueRef dady_ptr,
LLVMValueRef x0,
- LLVMValueRef y0,
- int xstep,
- int ystep)
+ LLVMValueRef y0)
{
struct tgsi_parse_context parse;
struct tgsi_full_declaration *decl;
@@ -331,21 +380,19 @@ lp_build_interp_soa_init(struct lp_build_interp_soa_context *bld,
pos_init(bld, x0, y0);
attribs_init(bld);
-
- bld->xstep = xstep;
- bld->ystep = ystep;
-
- coeffs_update(bld);
}
/**
- * Advance the position and inputs with the xstep and ystep.
+ * Advance the position and inputs to the given quad within the block.
*/
void
-lp_build_interp_soa_update(struct lp_build_interp_soa_context *bld)
+lp_build_interp_soa_update(struct lp_build_interp_soa_context *bld,
+ int quad_index)
{
- pos_update(bld);
+ assert(quad_index < 4);
+
+ pos_update(bld, quad_index);
- attribs_update(bld);
+ attribs_update(bld, quad_index);
}
diff --git a/src/gallium/drivers/llvmpipe/lp_bld_interp.h b/src/gallium/drivers/llvmpipe/lp_bld_interp.h
index 9c57a10879..e2b3bc1bf0 100644
--- a/src/gallium/drivers/llvmpipe/lp_bld_interp.h
+++ b/src/gallium/drivers/llvmpipe/lp_bld_interp.h
@@ -63,9 +63,6 @@ struct lp_build_interp_soa_context
LLVMValueRef dadx[1 + PIPE_MAX_SHADER_INPUTS][NUM_CHANNELS];
LLVMValueRef dady[1 + PIPE_MAX_SHADER_INPUTS][NUM_CHANNELS];
- int xstep;
- int ystep;
-
/* Attribute values before perspective divide */
LLVMValueRef attribs_pre[1 + PIPE_MAX_SHADER_INPUTS][NUM_CHANNELS];
@@ -88,12 +85,11 @@ lp_build_interp_soa_init(struct lp_build_interp_soa_context *bld,
LLVMValueRef dadx_ptr,
LLVMValueRef dady_ptr,
LLVMValueRef x0,
- LLVMValueRef y0,
- int xstep,
- int ystep);
+ LLVMValueRef y0);
void
-lp_build_interp_soa_update(struct lp_build_interp_soa_context *bld);
+lp_build_interp_soa_update(struct lp_build_interp_soa_context *bld,
+ int quad_index);
#endif /* LP_BLD_INTERP_H */
diff --git a/src/gallium/drivers/llvmpipe/lp_bld_logic.c b/src/gallium/drivers/llvmpipe/lp_bld_logic.c
index db22a8028a..d094a040d6 100644
--- a/src/gallium/drivers/llvmpipe/lp_bld_logic.c
+++ b/src/gallium/drivers/llvmpipe/lp_bld_logic.c
@@ -41,13 +41,17 @@
#include "lp_bld_logic.h"
+/**
+ * Build code to compare two values 'a' and 'b' of 'type' using the given func.
+ * \param func one of PIPE_FUNC_x
+ */
LLVMValueRef
-lp_build_cmp(struct lp_build_context *bld,
- unsigned func,
- LLVMValueRef a,
- LLVMValueRef b)
+lp_build_compare(LLVMBuilderRef builder,
+ const struct lp_type type,
+ unsigned func,
+ LLVMValueRef a,
+ LLVMValueRef b)
{
- const struct lp_type type = bld->type;
LLVMTypeRef vec_type = lp_build_vec_type(type);
LLVMTypeRef int_vec_type = lp_build_int_vec_type(type);
LLVMValueRef zeros = LLVMConstNull(int_vec_type);
@@ -56,6 +60,9 @@ lp_build_cmp(struct lp_build_context *bld,
LLVMValueRef res;
unsigned i;
+ assert(func >= PIPE_FUNC_NEVER);
+ assert(func <= PIPE_FUNC_ALWAYS);
+
if(func == PIPE_FUNC_NEVER)
return zeros;
if(func == PIPE_FUNC_ALWAYS)
@@ -68,6 +75,7 @@ lp_build_cmp(struct lp_build_context *bld,
#if defined(PIPE_ARCH_X86) || defined(PIPE_ARCH_X86_64)
if(type.width * type.length == 128) {
if(type.floating && util_cpu_caps.has_sse) {
+ /* float[4] comparison */
LLVMValueRef args[3];
unsigned cc;
boolean swap;
@@ -96,7 +104,7 @@ lp_build_cmp(struct lp_build_context *bld,
break;
default:
assert(0);
- return bld->undef;
+ return lp_build_undef(type);
}
if(swap) {
@@ -109,14 +117,15 @@ lp_build_cmp(struct lp_build_context *bld,
}
args[2] = LLVMConstInt(LLVMInt8Type(), cc, 0);
- res = lp_build_intrinsic(bld->builder,
+ res = lp_build_intrinsic(builder,
"llvm.x86.sse.cmp.ps",
vec_type,
args, 3);
- res = LLVMBuildBitCast(bld->builder, res, int_vec_type, "");
+ res = LLVMBuildBitCast(builder, res, int_vec_type, "");
return res;
}
else if(util_cpu_caps.has_sse2) {
+ /* int[4] comparison */
static const struct {
unsigned swap:1;
unsigned eq:1;
@@ -152,7 +161,7 @@ lp_build_cmp(struct lp_build_context *bld,
break;
default:
assert(0);
- return bld->undef;
+ return lp_build_undef(type);
}
/* There are no signed byte and unsigned word/dword comparison
@@ -162,8 +171,8 @@ lp_build_cmp(struct lp_build_context *bld,
((type.width == 8 && type.sign) ||
(type.width != 8 && !type.sign))) {
LLVMValueRef msb = lp_build_int_const_scalar(type, (unsigned long long)1 << (type.width - 1));
- a = LLVMBuildXor(bld->builder, a, msb, "");
- b = LLVMBuildXor(bld->builder, b, msb, "");
+ a = LLVMBuildXor(builder, a, msb, "");
+ b = LLVMBuildXor(builder, b, msb, "");
}
if(table[func].swap) {
@@ -176,14 +185,14 @@ lp_build_cmp(struct lp_build_context *bld,
}
if(table[func].eq)
- res = lp_build_intrinsic(bld->builder, pcmpeq, vec_type, args, 2);
+ res = lp_build_intrinsic(builder, pcmpeq, vec_type, args, 2);
else if (table[func].gt)
- res = lp_build_intrinsic(bld->builder, pcmpgt, vec_type, args, 2);
+ res = lp_build_intrinsic(builder, pcmpgt, vec_type, args, 2);
else
res = LLVMConstNull(vec_type);
if(table[func].not)
- res = LLVMBuildNot(bld->builder, res, "");
+ res = LLVMBuildNot(builder, res, "");
return res;
}
@@ -219,28 +228,28 @@ lp_build_cmp(struct lp_build_context *bld,
break;
default:
assert(0);
- return bld->undef;
+ return lp_build_undef(type);
}
#if 0
/* XXX: Although valid IR, no LLVM target currently support this */
- cond = LLVMBuildFCmp(bld->builder, op, a, b, "");
- res = LLVMBuildSelect(bld->builder, cond, ones, zeros, "");
+ cond = LLVMBuildFCmp(builder, op, a, b, "");
+ res = LLVMBuildSelect(builder, cond, ones, zeros, "");
#else
debug_printf("%s: warning: using slow element-wise vector comparison\n",
__FUNCTION__);
res = LLVMGetUndef(int_vec_type);
for(i = 0; i < type.length; ++i) {
LLVMValueRef index = LLVMConstInt(LLVMInt32Type(), i, 0);
- cond = LLVMBuildFCmp(bld->builder, op,
- LLVMBuildExtractElement(bld->builder, a, index, ""),
- LLVMBuildExtractElement(bld->builder, b, index, ""),
+ cond = LLVMBuildFCmp(builder, op,
+ LLVMBuildExtractElement(builder, a, index, ""),
+ LLVMBuildExtractElement(builder, b, index, ""),
"");
- cond = LLVMBuildSelect(bld->builder, cond,
+ cond = LLVMBuildSelect(builder, cond,
LLVMConstExtractElement(ones, index),
LLVMConstExtractElement(zeros, index),
"");
- res = LLVMBuildInsertElement(bld->builder, res, cond, index, "");
+ res = LLVMBuildInsertElement(builder, res, cond, index, "");
}
#endif
}
@@ -267,28 +276,28 @@ lp_build_cmp(struct lp_build_context *bld,
break;
default:
assert(0);
- return bld->undef;
+ return lp_build_undef(type);
}
#if 0
/* XXX: Although valid IR, no LLVM target currently support this */
- cond = LLVMBuildICmp(bld->builder, op, a, b, "");
- res = LLVMBuildSelect(bld->builder, cond, ones, zeros, "");
+ cond = LLVMBuildICmp(builder, op, a, b, "");
+ res = LLVMBuildSelect(builder, cond, ones, zeros, "");
#else
- debug_printf("%s: warning: using slow element-wise vector comparison\n",
+ debug_printf("%s: warning: using slow element-wise int vector comparison\n",
__FUNCTION__);
res = LLVMGetUndef(int_vec_type);
for(i = 0; i < type.length; ++i) {
LLVMValueRef index = LLVMConstInt(LLVMInt32Type(), i, 0);
- cond = LLVMBuildICmp(bld->builder, op,
- LLVMBuildExtractElement(bld->builder, a, index, ""),
- LLVMBuildExtractElement(bld->builder, b, index, ""),
+ cond = LLVMBuildICmp(builder, op,
+ LLVMBuildExtractElement(builder, a, index, ""),
+ LLVMBuildExtractElement(builder, b, index, ""),
"");
- cond = LLVMBuildSelect(bld->builder, cond,
+ cond = LLVMBuildSelect(builder, cond,
LLVMConstExtractElement(ones, index),
LLVMConstExtractElement(zeros, index),
"");
- res = LLVMBuildInsertElement(bld->builder, res, cond, index, "");
+ res = LLVMBuildInsertElement(builder, res, cond, index, "");
}
#endif
}
@@ -297,6 +306,21 @@ lp_build_cmp(struct lp_build_context *bld,
}
+
+/**
+ * Build code to compare two values 'a' and 'b' using the given func.
+ * \param func one of PIPE_FUNC_x
+ */
+LLVMValueRef
+lp_build_cmp(struct lp_build_context *bld,
+ unsigned func,
+ LLVMValueRef a,
+ LLVMValueRef b)
+{
+ return lp_build_compare(bld->builder, bld->type, func, a, b);
+}
+
+
LLVMValueRef
lp_build_select(struct lp_build_context *bld,
LLVMValueRef mask,
diff --git a/src/gallium/drivers/llvmpipe/lp_bld_logic.h b/src/gallium/drivers/llvmpipe/lp_bld_logic.h
index d67500ef70..40d64eb2c1 100644
--- a/src/gallium/drivers/llvmpipe/lp_bld_logic.h
+++ b/src/gallium/drivers/llvmpipe/lp_bld_logic.h
@@ -46,6 +46,14 @@ struct lp_type;
struct lp_build_context;
+LLVMValueRef
+lp_build_compare(LLVMBuilderRef builder,
+ const struct lp_type type,
+ unsigned func,
+ LLVMValueRef a,
+ LLVMValueRef b);
+
+
/**
* @param func is one of PIPE_FUNC_xxx
*/
diff --git a/src/gallium/drivers/llvmpipe/lp_bld_type.c b/src/gallium/drivers/llvmpipe/lp_bld_type.c
index 1320a26721..8270cd057f 100644
--- a/src/gallium/drivers/llvmpipe/lp_bld_type.c
+++ b/src/gallium/drivers/llvmpipe/lp_bld_type.c
@@ -157,6 +157,27 @@ lp_build_int_vec_type(struct lp_type type)
}
+/**
+ * Build int32[4] vector type
+ */
+LLVMTypeRef
+lp_build_int32_vec4_type(void)
+{
+ struct lp_type t;
+ LLVMTypeRef type;
+
+ memset(&t, 0, sizeof(t));
+ t.floating = FALSE; /* floating point values */
+ t.sign = TRUE; /* values are signed */
+ t.norm = FALSE; /* values are not limited to [0,1] or [-1,1] */
+ t.width = 32; /* 32-bit int */
+ t.length = 4; /* 4 elements per vector */
+
+ type = lp_build_int_elem_type(t);
+ return LLVMVectorType(type, t.length);
+}
+
+
struct lp_type
lp_int_type(struct lp_type type)
{
diff --git a/src/gallium/drivers/llvmpipe/lp_bld_type.h b/src/gallium/drivers/llvmpipe/lp_bld_type.h
index 2fb233d335..b7d8aed396 100644
--- a/src/gallium/drivers/llvmpipe/lp_bld_type.h
+++ b/src/gallium/drivers/llvmpipe/lp_bld_type.h
@@ -252,6 +252,10 @@ LLVMTypeRef
lp_build_int_vec_type(struct lp_type type);
+LLVMTypeRef
+lp_build_int32_vec4_type();
+
+
struct lp_type
lp_int_type(struct lp_type type);
diff --git a/src/gallium/drivers/llvmpipe/lp_buffer.c b/src/gallium/drivers/llvmpipe/lp_buffer.c
index 66f1f8e138..a5ef221a21 100644
--- a/src/gallium/drivers/llvmpipe/lp_buffer.c
+++ b/src/gallium/drivers/llvmpipe/lp_buffer.c
@@ -108,32 +108,6 @@ llvmpipe_user_buffer_create(struct pipe_screen *screen,
}
-static void
-llvmpipe_fence_reference(struct pipe_screen *screen,
- struct pipe_fence_handle **ptr,
- struct pipe_fence_handle *fence)
-{
-}
-
-
-static int
-llvmpipe_fence_signalled(struct pipe_screen *screen,
- struct pipe_fence_handle *fence,
- unsigned flag)
-{
- return 0;
-}
-
-
-static int
-llvmpipe_fence_finish(struct pipe_screen *screen,
- struct pipe_fence_handle *fence,
- unsigned flag)
-{
- return 0;
-}
-
-
void
llvmpipe_init_screen_buffer_funcs(struct pipe_screen *screen)
{
@@ -142,9 +116,4 @@ llvmpipe_init_screen_buffer_funcs(struct pipe_screen *screen)
screen->buffer_map = llvmpipe_buffer_map;
screen->buffer_unmap = llvmpipe_buffer_unmap;
screen->buffer_destroy = llvmpipe_buffer_destroy;
-
- screen->fence_reference = llvmpipe_fence_reference;
- screen->fence_signalled = llvmpipe_fence_signalled;
- screen->fence_finish = llvmpipe_fence_finish;
-
}
diff --git a/src/gallium/drivers/llvmpipe/lp_clear.c b/src/gallium/drivers/llvmpipe/lp_clear.c
index 08d9f2e273..3e8c410925 100644
--- a/src/gallium/drivers/llvmpipe/lp_clear.c
+++ b/src/gallium/drivers/llvmpipe/lp_clear.c
@@ -33,12 +33,9 @@
#include "pipe/p_defines.h"
-#include "util/u_pack_color.h"
#include "lp_clear.h"
#include "lp_context.h"
-#include "lp_surface.h"
-#include "lp_state.h"
-#include "lp_tile_cache.h"
+#include "lp_setup.h"
/**
@@ -46,37 +43,16 @@
* No masking, no scissor (clear entire buffer).
*/
void
-llvmpipe_clear(struct pipe_context *pipe, unsigned buffers, const float *rgba,
- double depth, unsigned stencil)
+llvmpipe_clear(struct pipe_context *pipe,
+ unsigned buffers,
+ const float *rgba,
+ double depth,
+ unsigned stencil)
{
struct llvmpipe_context *llvmpipe = llvmpipe_context(pipe);
- union util_color uc;
- unsigned cv;
- uint i;
if (llvmpipe->no_rast)
return;
-#if 0
- llvmpipe_update_derived(llvmpipe); /* not needed?? */
-#endif
-
- if (buffers & PIPE_CLEAR_COLOR) {
- for (i = 0; i < llvmpipe->framebuffer.nr_cbufs; i++) {
- struct pipe_surface *ps = llvmpipe->framebuffer.cbufs[i];
-
- util_pack_color(rgba, ps->format, &uc);
- lp_tile_cache_clear(llvmpipe->cbuf_cache[i], rgba, uc.ui);
- }
- llvmpipe->dirty_render_cache = TRUE;
- }
-
- if (buffers & PIPE_CLEAR_DEPTHSTENCIL) {
- struct pipe_surface *ps = llvmpipe->framebuffer.zsbuf;
-
- cv = util_pack_z_stencil(ps->format, depth, stencil);
-
- /* non-cached surface */
- pipe->surface_fill(pipe, ps, 0, 0, ps->width, ps->height, cv);
- }
+ lp_setup_clear( llvmpipe->setup, rgba, depth, stencil, buffers );
}
diff --git a/src/gallium/drivers/llvmpipe/lp_context.c b/src/gallium/drivers/llvmpipe/lp_context.c
index 1cc3c9227c..8d965175f8 100644
--- a/src/gallium/drivers/llvmpipe/lp_context.c
+++ b/src/gallium/drivers/llvmpipe/lp_context.c
@@ -38,65 +38,15 @@
#include "lp_clear.h"
#include "lp_context.h"
#include "lp_flush.h"
-#include "lp_prim_vbuf.h"
#include "lp_state.h"
#include "lp_surface.h"
-#include "lp_tile_cache.h"
-#include "lp_tex_cache.h"
#include "lp_texture.h"
#include "lp_winsys.h"
#include "lp_query.h"
+#include "lp_setup.h"
-/**
- * Map any drawing surfaces which aren't already mapped
- */
-void
-llvmpipe_map_transfers(struct llvmpipe_context *lp)
-{
- struct pipe_screen *screen = lp->pipe.screen;
- struct pipe_surface *zsbuf = lp->framebuffer.zsbuf;
- unsigned i;
-
- for (i = 0; i < lp->framebuffer.nr_cbufs; i++) {
- lp_tile_cache_map_transfers(lp->cbuf_cache[i]);
- }
-
- if(zsbuf) {
- if(!lp->zsbuf_transfer)
- lp->zsbuf_transfer = screen->get_tex_transfer(screen, zsbuf->texture,
- zsbuf->face, zsbuf->level, zsbuf->zslice,
- PIPE_TRANSFER_READ_WRITE,
- 0, 0, zsbuf->width, zsbuf->height);
- if(lp->zsbuf_transfer && !lp->zsbuf_map)
- lp->zsbuf_map = screen->transfer_map(screen, lp->zsbuf_transfer);
-
- }
-}
-
-
-/**
- * Unmap any mapped drawing surfaces
- */
-void
-llvmpipe_unmap_transfers(struct llvmpipe_context *lp)
-{
- uint i;
-
- for (i = 0; i < lp->framebuffer.nr_cbufs; i++) {
- lp_tile_cache_unmap_transfers(lp->cbuf_cache[i]);
- }
-
- if(lp->zsbuf_transfer) {
- struct pipe_screen *screen = lp->pipe.screen;
-
- if(lp->zsbuf_map) {
- screen->transfer_unmap(screen, lp->zsbuf_transfer);
- lp->zsbuf_map = NULL;
- }
- }
-}
static void llvmpipe_destroy( struct pipe_context *pipe )
@@ -104,22 +54,22 @@ static void llvmpipe_destroy( struct pipe_context *pipe )
struct llvmpipe_context *llvmpipe = llvmpipe_context( pipe );
uint i;
+ /* This will also destroy llvmpipe->setup:
+ */
if (llvmpipe->draw)
draw_destroy( llvmpipe->draw );
for (i = 0; i < PIPE_MAX_COLOR_BUFS; i++) {
- lp_destroy_tile_cache(llvmpipe->cbuf_cache[i]);
pipe_surface_reference(&llvmpipe->framebuffer.cbufs[i], NULL);
}
+
pipe_surface_reference(&llvmpipe->framebuffer.zsbuf, NULL);
for (i = 0; i < PIPE_MAX_SAMPLERS; i++) {
- lp_destroy_tex_tile_cache(llvmpipe->tex_cache[i]);
pipe_texture_reference(&llvmpipe->texture[i], NULL);
}
for (i = 0; i < PIPE_MAX_VERTEX_SAMPLERS; i++) {
- lp_destroy_tex_tile_cache(llvmpipe->vertex_tex_cache[i]);
pipe_texture_reference(&llvmpipe->vertex_textures[i], NULL);
}
@@ -138,33 +88,8 @@ llvmpipe_is_texture_referenced( struct pipe_context *pipe,
unsigned face, unsigned level)
{
struct llvmpipe_context *llvmpipe = llvmpipe_context( pipe );
- unsigned i;
-
- /* check if any of the bound drawing surfaces are this texture */
- if(llvmpipe->dirty_render_cache) {
- for (i = 0; i < llvmpipe->framebuffer.nr_cbufs; i++) {
- if(llvmpipe->framebuffer.cbufs[i] &&
- llvmpipe->framebuffer.cbufs[i]->texture == texture)
- return PIPE_REFERENCED_FOR_WRITE;
- }
- if(llvmpipe->framebuffer.zsbuf &&
- llvmpipe->framebuffer.zsbuf->texture == texture)
- return PIPE_REFERENCED_FOR_WRITE;
- }
- /* check if any of the tex_cache textures are this texture */
- for (i = 0; i < PIPE_MAX_SAMPLERS; i++) {
- if (llvmpipe->tex_cache[i] &&
- llvmpipe->tex_cache[i]->texture == texture)
- return PIPE_REFERENCED_FOR_READ;
- }
- for (i = 0; i < PIPE_MAX_VERTEX_SAMPLERS; i++) {
- if (llvmpipe->vertex_tex_cache[i] &&
- llvmpipe->vertex_tex_cache[i]->texture == texture)
- return PIPE_REFERENCED_FOR_READ;
- }
-
- return PIPE_UNREFERENCED;
+ return lp_setup_is_texture_referenced(llvmpipe->setup, texture);
}
static unsigned int
@@ -178,7 +103,6 @@ struct pipe_context *
llvmpipe_create( struct pipe_screen *screen )
{
struct llvmpipe_context *llvmpipe;
- uint i;
llvmpipe = align_malloc(sizeof(struct llvmpipe_context), 16);
if (!llvmpipe)
@@ -245,18 +169,6 @@ llvmpipe_create( struct pipe_screen *screen )
llvmpipe_init_texture_funcs( llvmpipe );
/*
- * Alloc caches for accessing drawing surfaces and textures.
- */
- for (i = 0; i < PIPE_MAX_COLOR_BUFS; i++)
- llvmpipe->cbuf_cache[i] = lp_create_tile_cache( screen );
-
- for (i = 0; i < PIPE_MAX_SAMPLERS; i++)
- llvmpipe->tex_cache[i] = lp_create_tex_tile_cache( screen );
- for (i = 0; i < PIPE_MAX_VERTEX_SAMPLERS; i++)
- llvmpipe->vertex_tex_cache[i] = lp_create_tex_tile_cache(screen);
-
-
- /*
* Create drawing context and plug our rendering stage into it.
*/
llvmpipe->draw = draw_create();
@@ -268,19 +180,11 @@ llvmpipe_create( struct pipe_screen *screen )
if (debug_get_bool_option( "LP_NO_RAST", FALSE ))
llvmpipe->no_rast = TRUE;
- llvmpipe->vbuf_backend = lp_create_vbuf_backend(llvmpipe);
- if (!llvmpipe->vbuf_backend)
+ llvmpipe->setup = lp_setup_create( screen,
+ llvmpipe->draw );
+ if (!llvmpipe->setup)
goto fail;
- llvmpipe->vbuf = draw_vbuf_stage(llvmpipe->draw, llvmpipe->vbuf_backend);
- if (!llvmpipe->vbuf)
- goto fail;
-
- draw_set_rasterize_stage(llvmpipe->draw, llvmpipe->vbuf);
- draw_set_render(llvmpipe->draw, llvmpipe->vbuf_backend);
-
-
-
/* plug in AA line/point stages */
draw_install_aaline_stage(llvmpipe->draw, &llvmpipe->pipe);
draw_install_aapoint_stage(llvmpipe->draw, &llvmpipe->pipe);
diff --git a/src/gallium/drivers/llvmpipe/lp_context.h b/src/gallium/drivers/llvmpipe/lp_context.h
index 6411797cf5..1ede6a6a72 100644
--- a/src/gallium/drivers/llvmpipe/lp_context.h
+++ b/src/gallium/drivers/llvmpipe/lp_context.h
@@ -42,12 +42,10 @@
struct llvmpipe_vbuf_render;
struct draw_context;
struct draw_stage;
-struct llvmpipe_tile_cache;
-struct llvmpipe_tex_tile_cache;
struct lp_fragment_shader;
struct lp_vertex_shader;
struct lp_blend_state;
-
+struct setup_context;
struct llvmpipe_context {
struct pipe_context pipe; /**< base class */
@@ -62,7 +60,7 @@ struct llvmpipe_context {
const struct lp_vertex_shader *vs;
/** Other rendering state */
- struct pipe_blend_color blend_color[4][16];
+ struct pipe_blend_color blend_color;
struct pipe_clip_state clip;
struct pipe_constant_buffer constants[PIPE_SHADER_TYPES];
struct pipe_framebuffer_state framebuffer;
@@ -94,49 +92,22 @@ struct llvmpipe_context {
/** Vertex format */
struct vertex_info vertex_info;
- struct vertex_info vertex_info_vbuf;
/** Which vertex shader output slot contains point size */
int psize_slot;
- /* The reduced version of the primitive supplied by the state
- * tracker.
- */
- unsigned reduced_api_prim;
-
- /* The reduced primitive after unfilled triangles, wide-line
- * decomposition, etc, are taken into account. This is the
- * primitive actually rasterized.
- */
- unsigned reduced_prim;
-
/** Derived from scissor and surface bounds: */
struct pipe_scissor_state cliprect;
- unsigned line_stipple_counter;
+ /** The tiling engine */
+ struct setup_context *setup;
/** The primitive drawing context */
struct draw_context *draw;
- /** Draw module backend */
- struct vbuf_render *vbuf_backend;
- struct draw_stage *vbuf;
-
- boolean dirty_render_cache;
-
- struct llvmpipe_tile_cache *cbuf_cache[PIPE_MAX_COLOR_BUFS];
-
- /* TODO: we shouldn't be using external interfaces internally like this */
- struct pipe_transfer *zsbuf_transfer;
- uint8_t *zsbuf_map;
-
unsigned tex_timestamp;
- struct llvmpipe_tex_tile_cache *tex_cache[PIPE_MAX_SAMPLERS];
- struct llvmpipe_tex_tile_cache *vertex_tex_cache[PIPE_MAX_VERTEX_SAMPLERS];
-
- unsigned no_rast : 1;
+ boolean no_rast;
- struct lp_jit_context jit_context;
};
diff --git a/src/gallium/drivers/llvmpipe/lp_draw_arrays.c b/src/gallium/drivers/llvmpipe/lp_draw_arrays.c
index c152b4413f..3989cce744 100644
--- a/src/gallium/drivers/llvmpipe/lp_draw_arrays.c
+++ b/src/gallium/drivers/llvmpipe/lp_draw_arrays.c
@@ -70,13 +70,9 @@ llvmpipe_draw_range_elements(struct pipe_context *pipe,
struct draw_context *draw = lp->draw;
unsigned i;
- lp->reduced_api_prim = u_reduced_prim(mode);
-
if (lp->dirty)
llvmpipe_update_derived( lp );
- llvmpipe_map_transfers(lp);
-
/*
* Map vertex buffers
*/
@@ -118,10 +114,6 @@ llvmpipe_draw_range_elements(struct pipe_context *pipe,
* internally when this condition is seen?)
*/
draw_flush(draw);
-
- /* Note: leave drawing surfaces mapped */
-
- lp->dirty_render_cache = TRUE;
}
diff --git a/src/gallium/drivers/llvmpipe/lp_fence.c b/src/gallium/drivers/llvmpipe/lp_fence.c
new file mode 100644
index 0000000000..97c46087da
--- /dev/null
+++ b/src/gallium/drivers/llvmpipe/lp_fence.c
@@ -0,0 +1,109 @@
+/**************************************************************************
+ *
+ * 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.
+ *
+ **************************************************************************/
+
+
+#include "pipe/p_screen.h"
+#include "util/u_memory.h"
+#include "lp_fence.h"
+
+
+struct lp_fence *
+lp_fence_create(unsigned rank)
+{
+ struct lp_fence *fence = CALLOC_STRUCT(lp_fence);
+
+ pipe_reference_init(&fence->reference, 1);
+
+ pipe_mutex_init(fence->mutex);
+ pipe_condvar_init(fence->signalled);
+
+ fence->rank = rank;
+
+ return fence;
+}
+
+
+static void
+lp_fence_destroy(struct lp_fence *fence)
+{
+ pipe_mutex_destroy(fence->mutex);
+ pipe_condvar_destroy(fence->signalled);
+ FREE(fence);
+}
+
+
+static void
+llvmpipe_fence_reference(struct pipe_screen *screen,
+ struct pipe_fence_handle **ptr,
+ struct pipe_fence_handle *fence)
+{
+ struct lp_fence *old = (struct lp_fence *) *ptr;
+ struct lp_fence *f = (struct lp_fence *) fence;
+
+ if (pipe_reference(&old->reference, &f->reference)) {
+ lp_fence_destroy(old);
+ }
+}
+
+
+static int
+llvmpipe_fence_signalled(struct pipe_screen *screen,
+ struct pipe_fence_handle *fence,
+ unsigned flag)
+{
+ struct lp_fence *f = (struct lp_fence *) fence;
+
+ return f->count == f->rank;
+}
+
+
+static int
+llvmpipe_fence_finish(struct pipe_screen *screen,
+ struct pipe_fence_handle *fence_handle,
+ unsigned flag)
+{
+ struct lp_fence *fence = (struct lp_fence *) fence_handle;
+
+ pipe_mutex_lock(fence->mutex);
+ while (fence->count < fence->rank) {
+ pipe_condvar_wait(fence->signalled, fence->mutex);
+ }
+ pipe_mutex_unlock(fence->mutex);
+
+ return 0;
+}
+
+
+
+
+void
+llvmpipe_init_screen_fence_funcs(struct pipe_screen *screen)
+{
+ screen->fence_reference = llvmpipe_fence_reference;
+ screen->fence_signalled = llvmpipe_fence_signalled;
+ screen->fence_finish = llvmpipe_fence_finish;
+}
diff --git a/src/gallium/drivers/llvmpipe/lp_fence.h b/src/gallium/drivers/llvmpipe/lp_fence.h
new file mode 100644
index 0000000000..d45318f9e4
--- /dev/null
+++ b/src/gallium/drivers/llvmpipe/lp_fence.h
@@ -0,0 +1,60 @@
+/**************************************************************************
+ *
+ * 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 LP_FENCE_H
+#define LP_FENCE_H
+
+
+#include "pipe/p_refcnt.h"
+#include "pipe/p_thread.h"
+
+
+struct pipe_screen;
+
+
+struct lp_fence
+{
+ struct pipe_reference reference;
+
+ pipe_mutex mutex;
+ pipe_condvar signalled;
+
+ unsigned rank;
+ unsigned count;
+};
+
+
+struct lp_fence *
+lp_fence_create(unsigned rank);
+
+
+void
+llvmpipe_init_screen_fence_funcs(struct pipe_screen *screen);
+
+
+#endif /* LP_FENCE_H */
diff --git a/src/gallium/drivers/llvmpipe/lp_flush.c b/src/gallium/drivers/llvmpipe/lp_flush.c
index cd8381fe30..9405150c4f 100644
--- a/src/gallium/drivers/llvmpipe/lp_flush.c
+++ b/src/gallium/drivers/llvmpipe/lp_flush.c
@@ -35,10 +35,8 @@
#include "lp_flush.h"
#include "lp_context.h"
#include "lp_surface.h"
-#include "lp_state.h"
-#include "lp_tile_cache.h"
-#include "lp_tex_cache.h"
#include "lp_winsys.h"
+#include "lp_setup.h"
void
@@ -47,40 +45,31 @@ llvmpipe_flush( struct pipe_context *pipe,
struct pipe_fence_handle **fence )
{
struct llvmpipe_context *llvmpipe = llvmpipe_context(pipe);
- uint i;
draw_flush(llvmpipe->draw);
- if (flags & PIPE_FLUSH_SWAPBUFFERS) {
- /* If this is a swapbuffers, just flush color buffers.
- *
- * The zbuffer changes are not discarded, but held in the cache
- * in the hope that a later clear will wipe them out.
- */
- for (i = 0; i < llvmpipe->framebuffer.nr_cbufs; i++)
- if (llvmpipe->cbuf_cache[i]) {
- lp_tile_cache_map_transfers(llvmpipe->cbuf_cache[i]);
- lp_flush_tile_cache(llvmpipe->cbuf_cache[i]);
- }
+ if (fence) {
+ if ((flags & (PIPE_FLUSH_SWAPBUFFERS |
+ PIPE_FLUSH_RENDER_CACHE))) {
+ /* if we're going to flush the setup/rasterization modules, emit
+ * a fence.
+ * XXX this (and the code below) may need fine tuning...
+ */
+ *fence = lp_setup_fence( llvmpipe->setup );
+ }
+ else {
+ *fence = NULL;
+ }
+ }
- /* Need this call for hardware buffers before swapbuffers.
- *
- * there should probably be another/different flush-type function
- * that's called before swapbuffers because we don't always want
- * to unmap surfaces when flushing.
- */
- llvmpipe_unmap_transfers(llvmpipe);
+ /* XXX the lp_setup_flush(flags) param is not a bool, and it's ignored
+ * at this time!
+ */
+ if (flags & PIPE_FLUSH_SWAPBUFFERS) {
+ lp_setup_flush( llvmpipe->setup, FALSE );
}
else if (flags & PIPE_FLUSH_RENDER_CACHE) {
- for (i = 0; i < llvmpipe->framebuffer.nr_cbufs; i++)
- if (llvmpipe->cbuf_cache[i]) {
- lp_tile_cache_map_transfers(llvmpipe->cbuf_cache[i]);
- lp_flush_tile_cache(llvmpipe->cbuf_cache[i]);
- }
-
- /* FIXME: untile zsbuf! */
-
- llvmpipe->dirty_render_cache = FALSE;
+ lp_setup_flush( llvmpipe->setup, TRUE );
}
/* Enable to dump BMPs of the color/depth buffers each frame */
@@ -95,8 +84,5 @@ llvmpipe_flush( struct pipe_context *pipe,
++frame_no;
}
#endif
-
- if (fence)
- *fence = NULL;
}
diff --git a/src/gallium/drivers/llvmpipe/lp_jit.h b/src/gallium/drivers/llvmpipe/lp_jit.h
index 277b690c02..1a6e939aa2 100644
--- a/src/gallium/drivers/llvmpipe/lp_jit.h
+++ b/src/gallium/drivers/llvmpipe/lp_jit.h
@@ -102,15 +102,21 @@ struct lp_jit_context
typedef void
-(*lp_jit_frag_func)(struct lp_jit_context *context,
+(*lp_jit_frag_func)(const struct lp_jit_context *context,
uint32_t x,
uint32_t y,
const void *a0,
const void *dadx,
const void *dady,
- uint32_t *mask,
void *color,
- void *depth);
+ void *depth,
+ const int32_t c1,
+ const int32_t c2,
+ const int32_t c3,
+ const int32_t *step1,
+ const int32_t *step2,
+ const int32_t *step3);
+
void
lp_jit_screen_cleanup(struct llvmpipe_screen *screen);
diff --git a/src/gallium/drivers/llvmpipe/lp_prim_vbuf.c b/src/gallium/drivers/llvmpipe/lp_prim_vbuf.c
deleted file mode 100644
index e8e2e2524a..0000000000
--- a/src/gallium/drivers/llvmpipe/lp_prim_vbuf.c
+++ /dev/null
@@ -1,563 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
- * 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 TUNGSTEN GRAPHICS 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.
- *
- **************************************************************************/
-
-/**
- * Interface between 'draw' module's output and the llvmpipe rasterizer/setup
- * code. When the 'draw' module has finished filling a vertex buffer, the
- * draw_arrays() functions below will be called. Loop over the vertices and
- * call the point/line/tri setup functions.
- *
- * Authors
- * Brian Paul
- */
-
-
-#include "lp_context.h"
-#include "lp_setup.h"
-#include "lp_state.h"
-#include "lp_prim_vbuf.h"
-#include "draw/draw_context.h"
-#include "draw/draw_vbuf.h"
-#include "util/u_memory.h"
-#include "util/u_prim.h"
-
-
-#define LP_MAX_VBUF_INDEXES 1024
-#define LP_MAX_VBUF_SIZE 4096
-
-typedef const float (*cptrf4)[4];
-
-/**
- * Subclass of vbuf_render.
- */
-struct llvmpipe_vbuf_render
-{
- struct vbuf_render base;
- struct llvmpipe_context *llvmpipe;
- struct setup_context *setup;
-
- uint prim;
- uint vertex_size;
- uint nr_vertices;
- uint vertex_buffer_size;
- void *vertex_buffer;
-};
-
-
-/** cast wrapper */
-static struct llvmpipe_vbuf_render *
-llvmpipe_vbuf_render(struct vbuf_render *vbr)
-{
- return (struct llvmpipe_vbuf_render *) vbr;
-}
-
-
-
-
-
-
-
-static const struct vertex_info *
-lp_vbuf_get_vertex_info(struct vbuf_render *vbr)
-{
- struct llvmpipe_vbuf_render *cvbr = llvmpipe_vbuf_render(vbr);
- return llvmpipe_get_vbuf_vertex_info(cvbr->llvmpipe);
-}
-
-
-static boolean
-lp_vbuf_allocate_vertices(struct vbuf_render *vbr,
- ushort vertex_size, ushort nr_vertices)
-{
- struct llvmpipe_vbuf_render *cvbr = llvmpipe_vbuf_render(vbr);
- unsigned size = vertex_size * nr_vertices;
-
- if (cvbr->vertex_buffer_size < size) {
- align_free(cvbr->vertex_buffer);
- cvbr->vertex_buffer = align_malloc(size, 16);
- cvbr->vertex_buffer_size = size;
- }
-
- cvbr->vertex_size = vertex_size;
- cvbr->nr_vertices = nr_vertices;
-
- return cvbr->vertex_buffer != NULL;
-}
-
-static void
-lp_vbuf_release_vertices(struct vbuf_render *vbr)
-{
- /* keep the old allocation for next time */
-}
-
-static void *
-lp_vbuf_map_vertices(struct vbuf_render *vbr)
-{
- struct llvmpipe_vbuf_render *cvbr = llvmpipe_vbuf_render(vbr);
- return cvbr->vertex_buffer;
-}
-
-static void
-lp_vbuf_unmap_vertices(struct vbuf_render *vbr,
- ushort min_index,
- ushort max_index )
-{
- struct llvmpipe_vbuf_render *cvbr = llvmpipe_vbuf_render(vbr);
- assert( cvbr->vertex_buffer_size >= (max_index+1) * cvbr->vertex_size );
- (void) cvbr;
- /* do nothing */
-}
-
-
-static boolean
-lp_vbuf_set_primitive(struct vbuf_render *vbr, unsigned prim)
-{
- struct llvmpipe_vbuf_render *cvbr = llvmpipe_vbuf_render(vbr);
- struct setup_context *setup_ctx = cvbr->setup;
-
- llvmpipe_setup_prepare( setup_ctx );
-
- cvbr->llvmpipe->reduced_prim = u_reduced_prim(prim);
- cvbr->prim = prim;
- return TRUE;
-
-}
-
-
-static INLINE cptrf4 get_vert( const void *vertex_buffer,
- int index,
- int stride )
-{
- return (cptrf4)((char *)vertex_buffer + index * stride);
-}
-
-
-/**
- * draw elements / indexed primitives
- */
-static void
-lp_vbuf_draw(struct vbuf_render *vbr, const ushort *indices, uint nr)
-{
- struct llvmpipe_vbuf_render *cvbr = llvmpipe_vbuf_render(vbr);
- struct llvmpipe_context *llvmpipe = cvbr->llvmpipe;
- const unsigned stride = llvmpipe->vertex_info_vbuf.size * sizeof(float);
- const void *vertex_buffer = cvbr->vertex_buffer;
- struct setup_context *setup_ctx = cvbr->setup;
- unsigned i;
-
- switch (cvbr->prim) {
- case PIPE_PRIM_POINTS:
- for (i = 0; i < nr; i++) {
- llvmpipe_setup_point( setup_ctx,
- get_vert(vertex_buffer, indices[i-0], stride) );
- }
- break;
-
- case PIPE_PRIM_LINES:
- for (i = 1; i < nr; i += 2) {
- llvmpipe_setup_line( setup_ctx,
- get_vert(vertex_buffer, indices[i-1], stride),
- get_vert(vertex_buffer, indices[i-0], stride) );
- }
- break;
-
- case PIPE_PRIM_LINE_STRIP:
- for (i = 1; i < nr; i ++) {
- llvmpipe_setup_line( setup_ctx,
- get_vert(vertex_buffer, indices[i-1], stride),
- get_vert(vertex_buffer, indices[i-0], stride) );
- }
- break;
-
- case PIPE_PRIM_LINE_LOOP:
- for (i = 1; i < nr; i ++) {
- llvmpipe_setup_line( setup_ctx,
- get_vert(vertex_buffer, indices[i-1], stride),
- get_vert(vertex_buffer, indices[i-0], stride) );
- }
- if (nr) {
- llvmpipe_setup_line( setup_ctx,
- get_vert(vertex_buffer, indices[nr-1], stride),
- get_vert(vertex_buffer, indices[0], stride) );
- }
- break;
-
- case PIPE_PRIM_TRIANGLES:
- if (llvmpipe->rasterizer->flatshade_first) {
- for (i = 2; i < nr; i += 3) {
- llvmpipe_setup_tri( setup_ctx,
- get_vert(vertex_buffer, indices[i-1], stride),
- get_vert(vertex_buffer, indices[i-0], stride),
- get_vert(vertex_buffer, indices[i-2], stride) );
- }
- }
- else {
- for (i = 2; i < nr; i += 3) {
- llvmpipe_setup_tri( setup_ctx,
- get_vert(vertex_buffer, indices[i-2], stride),
- get_vert(vertex_buffer, indices[i-1], stride),
- get_vert(vertex_buffer, indices[i-0], stride) );
- }
- }
- break;
-
- case PIPE_PRIM_TRIANGLE_STRIP:
- if (llvmpipe->rasterizer->flatshade_first) {
- for (i = 2; i < nr; i += 1) {
- llvmpipe_setup_tri( setup_ctx,
- get_vert(vertex_buffer, indices[i+(i&1)-1], stride),
- get_vert(vertex_buffer, indices[i-(i&1)], stride),
- get_vert(vertex_buffer, indices[i-2], stride) );
- }
- }
- else {
- for (i = 2; i < nr; i += 1) {
- llvmpipe_setup_tri( setup_ctx,
- get_vert(vertex_buffer, indices[i+(i&1)-2], stride),
- get_vert(vertex_buffer, indices[i-(i&1)-1], stride),
- get_vert(vertex_buffer, indices[i-0], stride) );
- }
- }
- break;
-
- case PIPE_PRIM_TRIANGLE_FAN:
- if (llvmpipe->rasterizer->flatshade_first) {
- for (i = 2; i < nr; i += 1) {
- llvmpipe_setup_tri( setup_ctx,
- get_vert(vertex_buffer, indices[i-0], stride),
- get_vert(vertex_buffer, indices[0], stride),
- get_vert(vertex_buffer, indices[i-1], stride) );
- }
- }
- else {
- for (i = 2; i < nr; i += 1) {
- llvmpipe_setup_tri( setup_ctx,
- get_vert(vertex_buffer, indices[0], stride),
- get_vert(vertex_buffer, indices[i-1], stride),
- get_vert(vertex_buffer, indices[i-0], stride) );
- }
- }
- break;
-
- case PIPE_PRIM_QUADS:
- if (llvmpipe->rasterizer->flatshade_first) {
- for (i = 3; i < nr; i += 4) {
- llvmpipe_setup_tri( setup_ctx,
- get_vert(vertex_buffer, indices[i-2], stride),
- get_vert(vertex_buffer, indices[i-1], stride),
- get_vert(vertex_buffer, indices[i-3], stride) );
- llvmpipe_setup_tri( setup_ctx,
- get_vert(vertex_buffer, indices[i-1], stride),
- get_vert(vertex_buffer, indices[i-0], stride),
- get_vert(vertex_buffer, indices[i-3], stride) );
- }
- }
- else {
- for (i = 3; i < nr; i += 4) {
- llvmpipe_setup_tri( setup_ctx,
- get_vert(vertex_buffer, indices[i-3], stride),
- get_vert(vertex_buffer, indices[i-2], stride),
- get_vert(vertex_buffer, indices[i-0], stride) );
-
- llvmpipe_setup_tri( setup_ctx,
- get_vert(vertex_buffer, indices[i-2], stride),
- get_vert(vertex_buffer, indices[i-1], stride),
- get_vert(vertex_buffer, indices[i-0], stride) );
- }
- }
- break;
-
- case PIPE_PRIM_QUAD_STRIP:
- if (llvmpipe->rasterizer->flatshade_first) {
- for (i = 3; i < nr; i += 2) {
- llvmpipe_setup_tri( setup_ctx,
- get_vert(vertex_buffer, indices[i-0], stride),
- get_vert(vertex_buffer, indices[i-1], stride),
- get_vert(vertex_buffer, indices[i-3], stride));
- llvmpipe_setup_tri( setup_ctx,
- get_vert(vertex_buffer, indices[i-2], stride),
- get_vert(vertex_buffer, indices[i-0], stride),
- get_vert(vertex_buffer, indices[i-3], stride) );
- }
- }
- else {
- for (i = 3; i < nr; i += 2) {
- llvmpipe_setup_tri( setup_ctx,
- get_vert(vertex_buffer, indices[i-3], stride),
- get_vert(vertex_buffer, indices[i-2], stride),
- get_vert(vertex_buffer, indices[i-0], stride) );
- llvmpipe_setup_tri( setup_ctx,
- get_vert(vertex_buffer, indices[i-1], stride),
- get_vert(vertex_buffer, indices[i-3], stride),
- get_vert(vertex_buffer, indices[i-0], stride) );
- }
- }
- break;
-
- case PIPE_PRIM_POLYGON:
- /* Almost same as tri fan but the _first_ vertex specifies the flat
- * shading color. Note that the first polygon vertex is passed as
- * the last triangle vertex here.
- * flatshade_first state makes no difference.
- */
- for (i = 2; i < nr; i += 1) {
- llvmpipe_setup_tri( setup_ctx,
- get_vert(vertex_buffer, indices[i-0], stride),
- get_vert(vertex_buffer, indices[i-1], stride),
- get_vert(vertex_buffer, indices[0], stride) );
- }
- break;
-
- default:
- assert(0);
- }
-}
-
-
-/**
- * This function is hit when the draw module is working in pass-through mode.
- * It's up to us to convert the vertex array into point/line/tri prims.
- */
-static void
-lp_vbuf_draw_arrays(struct vbuf_render *vbr, uint start, uint nr)
-{
- struct llvmpipe_vbuf_render *cvbr = llvmpipe_vbuf_render(vbr);
- struct llvmpipe_context *llvmpipe = cvbr->llvmpipe;
- struct setup_context *setup_ctx = cvbr->setup;
- const unsigned stride = llvmpipe->vertex_info_vbuf.size * sizeof(float);
- const void *vertex_buffer =
- (void *) get_vert(cvbr->vertex_buffer, start, stride);
- unsigned i;
-
- switch (cvbr->prim) {
- case PIPE_PRIM_POINTS:
- for (i = 0; i < nr; i++) {
- llvmpipe_setup_point( setup_ctx,
- get_vert(vertex_buffer, i-0, stride) );
- }
- break;
-
- case PIPE_PRIM_LINES:
- for (i = 1; i < nr; i += 2) {
- llvmpipe_setup_line( setup_ctx,
- get_vert(vertex_buffer, i-1, stride),
- get_vert(vertex_buffer, i-0, stride) );
- }
- break;
-
- case PIPE_PRIM_LINE_STRIP:
- for (i = 1; i < nr; i ++) {
- llvmpipe_setup_line( setup_ctx,
- get_vert(vertex_buffer, i-1, stride),
- get_vert(vertex_buffer, i-0, stride) );
- }
- break;
-
- case PIPE_PRIM_LINE_LOOP:
- for (i = 1; i < nr; i ++) {
- llvmpipe_setup_line( setup_ctx,
- get_vert(vertex_buffer, i-1, stride),
- get_vert(vertex_buffer, i-0, stride) );
- }
- if (nr) {
- llvmpipe_setup_line( setup_ctx,
- get_vert(vertex_buffer, nr-1, stride),
- get_vert(vertex_buffer, 0, stride) );
- }
- break;
-
- case PIPE_PRIM_TRIANGLES:
- if (llvmpipe->rasterizer->flatshade_first) {
- for (i = 2; i < nr; i += 3) {
- llvmpipe_setup_tri( setup_ctx,
- get_vert(vertex_buffer, i-1, stride),
- get_vert(vertex_buffer, i-0, stride),
- get_vert(vertex_buffer, i-2, stride) );
- }
- }
- else {
- for (i = 2; i < nr; i += 3) {
- llvmpipe_setup_tri( setup_ctx,
- get_vert(vertex_buffer, i-2, stride),
- get_vert(vertex_buffer, i-1, stride),
- get_vert(vertex_buffer, i-0, stride) );
- }
- }
- break;
-
- case PIPE_PRIM_TRIANGLE_STRIP:
- if (llvmpipe->rasterizer->flatshade_first) {
- for (i = 2; i < nr; i++) {
- llvmpipe_setup_tri( setup_ctx,
- get_vert(vertex_buffer, i+(i&1)-1, stride),
- get_vert(vertex_buffer, i-(i&1), stride),
- get_vert(vertex_buffer, i-2, stride) );
- }
- }
- else {
- for (i = 2; i < nr; i++) {
- llvmpipe_setup_tri( setup_ctx,
- get_vert(vertex_buffer, i+(i&1)-2, stride),
- get_vert(vertex_buffer, i-(i&1)-1, stride),
- get_vert(vertex_buffer, i-0, stride) );
- }
- }
- break;
-
- case PIPE_PRIM_TRIANGLE_FAN:
- if (llvmpipe->rasterizer->flatshade_first) {
- for (i = 2; i < nr; i += 1) {
- llvmpipe_setup_tri( setup_ctx,
- get_vert(vertex_buffer, i-0, stride),
- get_vert(vertex_buffer, 0, stride),
- get_vert(vertex_buffer, i-1, stride) );
- }
- }
- else {
- for (i = 2; i < nr; i += 1) {
- llvmpipe_setup_tri( setup_ctx,
- get_vert(vertex_buffer, 0, stride),
- get_vert(vertex_buffer, i-1, stride),
- get_vert(vertex_buffer, i-0, stride) );
- }
- }
- break;
-
- case PIPE_PRIM_QUADS:
- if (llvmpipe->rasterizer->flatshade_first) {
- for (i = 3; i < nr; i += 4) {
- llvmpipe_setup_tri( setup_ctx,
- get_vert(vertex_buffer, i-2, stride),
- get_vert(vertex_buffer, i-1, stride),
- get_vert(vertex_buffer, i-3, stride) );
- llvmpipe_setup_tri( setup_ctx,
- get_vert(vertex_buffer, i-1, stride),
- get_vert(vertex_buffer, i-0, stride),
- get_vert(vertex_buffer, i-3, stride) );
- }
- }
- else {
- for (i = 3; i < nr; i += 4) {
- llvmpipe_setup_tri( setup_ctx,
- get_vert(vertex_buffer, i-3, stride),
- get_vert(vertex_buffer, i-2, stride),
- get_vert(vertex_buffer, i-0, stride) );
- llvmpipe_setup_tri( setup_ctx,
- get_vert(vertex_buffer, i-2, stride),
- get_vert(vertex_buffer, i-1, stride),
- get_vert(vertex_buffer, i-0, stride) );
- }
- }
- break;
-
- case PIPE_PRIM_QUAD_STRIP:
- if (llvmpipe->rasterizer->flatshade_first) {
- for (i = 3; i < nr; i += 2) {
- llvmpipe_setup_tri( setup_ctx,
- get_vert(vertex_buffer, i-0, stride),
- get_vert(vertex_buffer, i-1, stride),
- get_vert(vertex_buffer, i-3, stride) );
- llvmpipe_setup_tri( setup_ctx,
- get_vert(vertex_buffer, i-2, stride),
- get_vert(vertex_buffer, i-0, stride),
- get_vert(vertex_buffer, i-3, stride) );
- }
- }
- else {
- for (i = 3; i < nr; i += 2) {
- llvmpipe_setup_tri( setup_ctx,
- get_vert(vertex_buffer, i-3, stride),
- get_vert(vertex_buffer, i-2, stride),
- get_vert(vertex_buffer, i-0, stride) );
- llvmpipe_setup_tri( setup_ctx,
- get_vert(vertex_buffer, i-1, stride),
- get_vert(vertex_buffer, i-3, stride),
- get_vert(vertex_buffer, i-0, stride) );
- }
- }
- break;
-
- case PIPE_PRIM_POLYGON:
- /* Almost same as tri fan but the _first_ vertex specifies the flat
- * shading color. Note that the first polygon vertex is passed as
- * the last triangle vertex here.
- * flatshade_first state makes no difference.
- */
- for (i = 2; i < nr; i += 1) {
- llvmpipe_setup_tri( setup_ctx,
- get_vert(vertex_buffer, i-1, stride),
- get_vert(vertex_buffer, i-0, stride),
- get_vert(vertex_buffer, 0, stride) );
- }
- break;
-
- default:
- assert(0);
- }
-}
-
-
-
-static void
-lp_vbuf_destroy(struct vbuf_render *vbr)
-{
- struct llvmpipe_vbuf_render *cvbr = llvmpipe_vbuf_render(vbr);
- llvmpipe_setup_destroy_context(cvbr->setup);
- FREE(cvbr);
-}
-
-
-/**
- * Create the post-transform vertex handler for the given context.
- */
-struct vbuf_render *
-lp_create_vbuf_backend(struct llvmpipe_context *lp)
-{
- struct llvmpipe_vbuf_render *cvbr = CALLOC_STRUCT(llvmpipe_vbuf_render);
-
- assert(lp->draw);
-
-
- cvbr->base.max_indices = LP_MAX_VBUF_INDEXES;
- cvbr->base.max_vertex_buffer_bytes = LP_MAX_VBUF_SIZE;
-
- cvbr->base.get_vertex_info = lp_vbuf_get_vertex_info;
- cvbr->base.allocate_vertices = lp_vbuf_allocate_vertices;
- cvbr->base.map_vertices = lp_vbuf_map_vertices;
- cvbr->base.unmap_vertices = lp_vbuf_unmap_vertices;
- cvbr->base.set_primitive = lp_vbuf_set_primitive;
- cvbr->base.draw = lp_vbuf_draw;
- cvbr->base.draw_arrays = lp_vbuf_draw_arrays;
- cvbr->base.release_vertices = lp_vbuf_release_vertices;
- cvbr->base.destroy = lp_vbuf_destroy;
-
- cvbr->llvmpipe = lp;
-
- cvbr->setup = llvmpipe_setup_create_context(cvbr->llvmpipe);
-
- return &cvbr->base;
-}
diff --git a/src/gallium/drivers/llvmpipe/lp_quad.h b/src/gallium/drivers/llvmpipe/lp_quad.h
deleted file mode 100644
index 7eb05de77a..0000000000
--- a/src/gallium/drivers/llvmpipe/lp_quad.h
+++ /dev/null
@@ -1,114 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
- * 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 TUNGSTEN GRAPHICS 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 <keith@tungstengraphics.com>
- */
-
-#ifndef LP_QUAD_H
-#define LP_QUAD_H
-
-#include "pipe/p_state.h"
-#include "tgsi/tgsi_exec.h"
-
-
-#define QUAD_PRIM_POINT 1
-#define QUAD_PRIM_LINE 2
-#define QUAD_PRIM_TRI 3
-
-
-/* The rasterizer generates 2x2 quads of fragment and feeds them to
- * the current fp_machine (see below).
- * Remember that Y=0=top with Y increasing down the window.
- */
-#define QUAD_TOP_LEFT 0
-#define QUAD_TOP_RIGHT 1
-#define QUAD_BOTTOM_LEFT 2
-#define QUAD_BOTTOM_RIGHT 3
-
-#define MASK_TOP_LEFT (1 << QUAD_TOP_LEFT)
-#define MASK_TOP_RIGHT (1 << QUAD_TOP_RIGHT)
-#define MASK_BOTTOM_LEFT (1 << QUAD_BOTTOM_LEFT)
-#define MASK_BOTTOM_RIGHT (1 << QUAD_BOTTOM_RIGHT)
-#define MASK_ALL 0xf
-
-
-/**
- * Quad stage inputs (pos, coverage, front/back face, etc)
- */
-struct quad_header_input
-{
- int x0, y0; /**< quad window pos, always even */
- float coverage[QUAD_SIZE]; /**< fragment coverage for antialiasing */
- unsigned facing:1; /**< Front (0) or back (1) facing? */
- unsigned prim:2; /**< QUAD_PRIM_POINT, LINE, TRI */
-};
-
-
-/**
- * Quad stage inputs/outputs.
- */
-struct quad_header_inout
-{
- unsigned mask:4;
-};
-
-
-/**
- * Quad stage outputs (color & depth).
- */
-struct quad_header_output
-{
- /** colors in SOA format (rrrr, gggg, bbbb, aaaa) */
- float ALIGN16_ATTRIB color[PIPE_MAX_COLOR_BUFS][NUM_CHANNELS][QUAD_SIZE];
-};
-
-
-/**
- * Input interpolation coefficients
- */
-struct quad_interp_coef
-{
- float ALIGN16_ATTRIB a0[1 + PIPE_MAX_SHADER_INPUTS][NUM_CHANNELS];
- float ALIGN16_ATTRIB dadx[1 + PIPE_MAX_SHADER_INPUTS][NUM_CHANNELS];
- float ALIGN16_ATTRIB dady[1 + PIPE_MAX_SHADER_INPUTS][NUM_CHANNELS];
-};
-
-
-/**
- * Encodes everything we need to know about a 2x2 pixel block. Uses
- * "Channel-Serial" or "SoA" layout.
- */
-struct quad_header {
- struct quad_header_input input;
- struct quad_header_inout inout;
-
- /* Redundant/duplicated:
- */
- const struct quad_interp_coef *coef;
-};
-
-#endif /* LP_QUAD_H */
diff --git a/src/gallium/drivers/llvmpipe/lp_rast.c b/src/gallium/drivers/llvmpipe/lp_rast.c
new file mode 100644
index 0000000000..6535e69308
--- /dev/null
+++ b/src/gallium/drivers/llvmpipe/lp_rast.c
@@ -0,0 +1,793 @@
+/**************************************************************************
+ *
+ * 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.
+ *
+ **************************************************************************/
+
+#include <limits.h>
+#include "util/u_memory.h"
+#include "util/u_math.h"
+#include "util/u_cpu_detect.h"
+#include "util/u_surface.h"
+
+#include "lp_scene_queue.h"
+#include "lp_debug.h"
+#include "lp_fence.h"
+#include "lp_rast.h"
+#include "lp_rast_priv.h"
+#include "lp_tile_soa.h"
+#include "lp_bld_debug.h"
+#include "lp_scene.h"
+
+
+/**
+ * Begin the rasterization phase.
+ * Map the framebuffer surfaces. Initialize the 'rast' state.
+ */
+static boolean
+lp_rast_begin( struct lp_rasterizer *rast,
+ const struct pipe_framebuffer_state *fb,
+ boolean write_color,
+ boolean write_zstencil )
+{
+ struct pipe_screen *screen = rast->screen;
+ struct pipe_surface *cbuf, *zsbuf;
+
+ LP_DBG(DEBUG_RAST, "%s\n", __FUNCTION__);
+
+ util_copy_framebuffer_state(&rast->state.fb, fb);
+
+ rast->state.write_zstencil = write_zstencil;
+ rast->state.write_color = write_color;
+
+ rast->check_for_clipped_tiles = (fb->width % TILE_SIZE != 0 ||
+ fb->height % TILE_SIZE != 0);
+
+ /* XXX support multiple color buffers here */
+ cbuf = rast->state.fb.cbufs[0];
+ if (cbuf) {
+ rast->cbuf_transfer = screen->get_tex_transfer(rast->screen,
+ cbuf->texture,
+ cbuf->face,
+ cbuf->level,
+ cbuf->zslice,
+ PIPE_TRANSFER_READ_WRITE,
+ 0, 0,
+ fb->width, fb->height);
+ if (!rast->cbuf_transfer)
+ return FALSE;
+
+ rast->cbuf_map = screen->transfer_map(rast->screen,
+ rast->cbuf_transfer);
+ if (!rast->cbuf_map)
+ return FALSE;
+ }
+
+ zsbuf = rast->state.fb.zsbuf;
+ if (zsbuf) {
+ rast->zsbuf_transfer = screen->get_tex_transfer(rast->screen,
+ zsbuf->texture,
+ zsbuf->face,
+ zsbuf->level,
+ zsbuf->zslice,
+ PIPE_TRANSFER_READ_WRITE,
+ 0, 0,
+ fb->width, fb->height);
+ if (!rast->zsbuf_transfer)
+ return FALSE;
+
+ rast->zsbuf_map = screen->transfer_map(rast->screen,
+ rast->zsbuf_transfer);
+ if (!rast->zsbuf_map)
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/**
+ * Finish the rasterization phase.
+ * Unmap framebuffer surfaces.
+ */
+static void
+lp_rast_end( struct lp_rasterizer *rast )
+{
+ struct pipe_screen *screen = rast->screen;
+
+ if (rast->cbuf_map)
+ screen->transfer_unmap(screen, rast->cbuf_transfer);
+
+ if (rast->zsbuf_map)
+ screen->transfer_unmap(screen, rast->zsbuf_transfer);
+
+ if (rast->cbuf_transfer)
+ screen->tex_transfer_destroy(rast->cbuf_transfer);
+
+ if (rast->zsbuf_transfer)
+ screen->tex_transfer_destroy(rast->zsbuf_transfer);
+
+ rast->cbuf_transfer = NULL;
+ rast->zsbuf_transfer = NULL;
+ rast->cbuf_map = NULL;
+ rast->zsbuf_map = NULL;
+}
+
+
+/**
+ * Begining rasterization of a tile.
+ * \param x window X position of the tile, in pixels
+ * \param y window Y position of the tile, in pixels
+ */
+static void
+lp_rast_start_tile( struct lp_rasterizer *rast,
+ unsigned thread_index,
+ unsigned x, unsigned y )
+{
+ LP_DBG(DEBUG_RAST, "%s %d,%d\n", __FUNCTION__, x, y);
+
+ rast->tasks[thread_index].x = x;
+ rast->tasks[thread_index].y = y;
+}
+
+
+/**
+ * Clear the rasterizer's current color tile.
+ * This is a bin command called during bin processing.
+ */
+void lp_rast_clear_color( struct lp_rasterizer *rast,
+ unsigned thread_index,
+ const union lp_rast_cmd_arg arg )
+{
+ const uint8_t *clear_color = arg.clear_color;
+ uint8_t *color_tile = rast->tasks[thread_index].tile.color;
+
+ LP_DBG(DEBUG_RAST, "%s 0x%x,0x%x,0x%x,0x%x\n", __FUNCTION__,
+ clear_color[0],
+ clear_color[1],
+ clear_color[2],
+ clear_color[3]);
+
+ if (clear_color[0] == clear_color[1] &&
+ clear_color[1] == clear_color[2] &&
+ clear_color[2] == clear_color[3]) {
+ memset(color_tile, clear_color[0], TILE_SIZE * TILE_SIZE * 4);
+ }
+ else {
+ unsigned x, y, chan;
+ for (y = 0; y < TILE_SIZE; y++)
+ for (x = 0; x < TILE_SIZE; x++)
+ for (chan = 0; chan < 4; ++chan)
+ TILE_PIXEL(color_tile, x, y, chan) = clear_color[chan];
+ }
+}
+
+
+/**
+ * Clear the rasterizer's current z/stencil tile.
+ * This is a bin command called during bin processing.
+ */
+void lp_rast_clear_zstencil( struct lp_rasterizer *rast,
+ unsigned thread_index,
+ const union lp_rast_cmd_arg arg)
+{
+ unsigned i, j;
+ uint32_t *depth_tile = rast->tasks[thread_index].tile.depth;
+
+ LP_DBG(DEBUG_RAST, "%s 0x%x\n", __FUNCTION__, arg.clear_zstencil);
+
+ for (i = 0; i < TILE_SIZE; i++)
+ for (j = 0; j < TILE_SIZE; j++)
+ depth_tile[i*TILE_SIZE + j] = arg.clear_zstencil;
+}
+
+
+/**
+ * Load tile color from the framebuffer surface.
+ * This is a bin command called during bin processing.
+ */
+void lp_rast_load_color( struct lp_rasterizer *rast,
+ unsigned thread_index,
+ const union lp_rast_cmd_arg arg)
+{
+ struct lp_rasterizer_task *task = &rast->tasks[thread_index];
+ const unsigned x = task->x;
+ const unsigned y = task->y;
+ int w = TILE_SIZE;
+ int h = TILE_SIZE;
+
+ LP_DBG(DEBUG_RAST, "%s at %u, %u\n", __FUNCTION__, x, y);
+
+ if (x + w > rast->state.fb.width)
+ w -= x + w - rast->state.fb.width;
+
+ if (y + h > rast->state.fb.height)
+ h -= y + h - rast->state.fb.height;
+
+ assert(w >= 0);
+ assert(h >= 0);
+ assert(w <= TILE_SIZE);
+ assert(h <= TILE_SIZE);
+
+ lp_tile_read_4ub(rast->cbuf_transfer->texture->format,
+ rast->tasks[thread_index].tile.color,
+ rast->cbuf_map,
+ rast->cbuf_transfer->stride,
+ x, y,
+ w, h);
+}
+
+
+/**
+ * Load tile z/stencil from the framebuffer surface.
+ * This is a bin command called during bin processing.
+ */
+void lp_rast_load_zstencil( struct lp_rasterizer *rast,
+ unsigned thread_index,
+ const union lp_rast_cmd_arg arg )
+{
+ LP_DBG(DEBUG_RAST, "%s\n", __FUNCTION__);
+
+ /* call u_tile func to load depth (and stencil?) from surface */
+}
+
+
+void lp_rast_set_state( struct lp_rasterizer *rast,
+ unsigned thread_index,
+ const union lp_rast_cmd_arg arg )
+{
+ const struct lp_rast_state *state = arg.set_state;
+
+ LP_DBG(DEBUG_RAST, "%s %p\n", __FUNCTION__, (void *) state);
+
+ /* just set the current state pointer for this rasterizer */
+ rast->tasks[thread_index].current_state = state;
+}
+
+
+
+/* Within a tile:
+ */
+
+/**
+ * Run the shader on all blocks in a tile. This is used when a tile is
+ * completely contained inside a triangle.
+ * This is a bin command called during bin processing.
+ */
+void lp_rast_shade_tile( struct lp_rasterizer *rast,
+ unsigned thread_index,
+ const union lp_rast_cmd_arg arg )
+{
+ /* Set c1,c2,c3 to large values so the in/out test always passes */
+ const int32_t c1 = INT_MIN, c2 = INT_MIN, c3 = INT_MIN;
+ const struct lp_rast_shader_inputs *inputs = arg.shade_tile;
+ const unsigned tile_x = rast->tasks[thread_index].x;
+ const unsigned tile_y = rast->tasks[thread_index].y;
+ unsigned x, y;
+
+ LP_DBG(DEBUG_RAST, "%s\n", __FUNCTION__);
+
+ /* Use the existing preference for 4x4 (four quads) shading:
+ */
+ for (y = 0; y < TILE_SIZE; y += 4)
+ for (x = 0; x < TILE_SIZE; x += 4)
+ lp_rast_shade_quads( rast,
+ thread_index,
+ inputs,
+ tile_x + x,
+ tile_y + y,
+ c1, c2, c3);
+}
+
+
+/**
+ * Compute shading for a 4x4 block of pixels.
+ * This is a bin command called during bin processing.
+ */
+void lp_rast_shade_quads( struct lp_rasterizer *rast,
+ unsigned thread_index,
+ const struct lp_rast_shader_inputs *inputs,
+ unsigned x, unsigned y,
+ int32_t c1, int32_t c2, int32_t c3)
+{
+ const struct lp_rast_state *state = rast->tasks[thread_index].current_state;
+ struct lp_rast_tile *tile = &rast->tasks[thread_index].tile;
+ void *color;
+ void *depth;
+ unsigned ix, iy;
+ int block_offset;
+
+#ifdef DEBUG
+ assert(state);
+
+ /* Sanity checks */
+ assert(x % TILE_VECTOR_WIDTH == 0);
+ assert(y % TILE_VECTOR_HEIGHT == 0);
+
+ assert((x % 4) == 0);
+ assert((y % 4) == 0);
+#endif
+
+ ix = x % TILE_SIZE;
+ iy = y % TILE_SIZE;
+
+ /* offset of the 16x16 pixel block within the tile */
+ block_offset = ((iy/4)*(16*16) + (ix/4)*16);
+
+ /* color buffer */
+ color = tile->color + 4 * block_offset;
+
+ /* depth buffer */
+ depth = tile->depth + block_offset;
+
+#ifdef DEBUG
+ assert(lp_check_alignment(depth, 16));
+ assert(lp_check_alignment(color, 16));
+ assert(lp_check_alignment(state->jit_context.blend_color, 16));
+
+ assert(lp_check_alignment(inputs->step[0], 16));
+ assert(lp_check_alignment(inputs->step[1], 16));
+ assert(lp_check_alignment(inputs->step[2], 16));
+#endif
+
+ /* run shader */
+ state->jit_function( &state->jit_context,
+ x, y,
+ inputs->a0,
+ inputs->dadx,
+ inputs->dady,
+ color,
+ depth,
+ c1, c2, c3,
+ inputs->step[0], inputs->step[1], inputs->step[2]
+ );
+}
+
+
+/* End of tile:
+ */
+
+
+/**
+ * Write the rasterizer's color tile to the framebuffer.
+ */
+static void lp_rast_store_color( struct lp_rasterizer *rast,
+ unsigned thread_index)
+{
+ const unsigned x = rast->tasks[thread_index].x;
+ const unsigned y = rast->tasks[thread_index].y;
+ int w = TILE_SIZE;
+ int h = TILE_SIZE;
+
+ if (x + w > rast->state.fb.width)
+ w -= x + w - rast->state.fb.width;
+
+ if (y + h > rast->state.fb.height)
+ h -= y + h - rast->state.fb.height;
+
+ assert(w >= 0);
+ assert(h >= 0);
+ assert(w <= TILE_SIZE);
+ assert(h <= TILE_SIZE);
+
+ LP_DBG(DEBUG_RAST, "%s [%u] %d,%d %dx%d\n", __FUNCTION__,
+ thread_index, x, y, w, h);
+
+ lp_tile_write_4ub(rast->cbuf_transfer->texture->format,
+ rast->tasks[thread_index].tile.color,
+ rast->cbuf_map,
+ rast->cbuf_transfer->stride,
+ x, y,
+ w, h);
+}
+
+
+static void
+lp_tile_write_z32(const uint32_t *src, uint8_t *dst, unsigned dst_stride,
+ unsigned x0, unsigned y0, unsigned w, unsigned h)
+{
+ unsigned x, y;
+ uint8_t *dst_row = dst + y0*dst_stride;
+ for (y = 0; y < h; ++y) {
+ uint32_t *dst_pixel = (uint32_t *)(dst_row + x0*4);
+ for (x = 0; x < w; ++x) {
+ *dst_pixel++ = *src++;
+ }
+ dst_row += dst_stride;
+ }
+}
+
+/**
+ * Write the rasterizer's z/stencil tile to the framebuffer.
+ */
+static void lp_rast_store_zstencil( struct lp_rasterizer *rast,
+ unsigned thread_index )
+{
+ const unsigned x = rast->tasks[thread_index].x;
+ const unsigned y = rast->tasks[thread_index].y;
+ unsigned w = TILE_SIZE;
+ unsigned h = TILE_SIZE;
+
+ if (x + w > rast->state.fb.width)
+ w -= x + w - rast->state.fb.width;
+
+ if (y + h > rast->state.fb.height)
+ h -= y + h - rast->state.fb.height;
+
+ LP_DBG(DEBUG_RAST, "%s %d,%d %dx%d\n", __FUNCTION__, x, y, w, h);
+
+ assert(rast->zsbuf_transfer->texture->format == PIPE_FORMAT_Z32_UNORM);
+ lp_tile_write_z32(rast->tasks[thread_index].tile.depth,
+ rast->zsbuf_map,
+ rast->zsbuf_transfer->stride,
+ x, y, w, h);
+}
+
+
+/**
+ * Write the rasterizer's tiles to the framebuffer.
+ */
+static void
+lp_rast_end_tile( struct lp_rasterizer *rast,
+ unsigned thread_index )
+{
+ LP_DBG(DEBUG_RAST, "%s\n", __FUNCTION__);
+
+ if (rast->state.write_color)
+ lp_rast_store_color(rast, thread_index);
+
+ if (rast->state.write_zstencil)
+ lp_rast_store_zstencil(rast, thread_index);
+}
+
+
+/**
+ * Signal on a fence. This is called during bin execution/rasterization.
+ * Called per thread.
+ */
+void lp_rast_fence( struct lp_rasterizer *rast,
+ unsigned thread_index,
+ const union lp_rast_cmd_arg arg )
+{
+ struct lp_fence *fence = arg.fence;
+
+ pipe_mutex_lock( fence->mutex );
+
+ fence->count++;
+ assert(fence->count <= fence->rank);
+
+ LP_DBG(DEBUG_RAST, "%s count=%u rank=%u\n", __FUNCTION__,
+ fence->count, fence->rank);
+
+ pipe_condvar_signal( fence->signalled );
+
+ pipe_mutex_unlock( fence->mutex );
+}
+
+
+/**
+ * When all the threads are done rasterizing a scene, one thread will
+ * call this function to reset the scene and put it onto the empty queue.
+ */
+static void
+release_scene( struct lp_rasterizer *rast,
+ struct lp_scene *scene )
+{
+ util_unreference_framebuffer_state( &scene->fb );
+
+ lp_scene_reset( scene );
+ lp_scene_enqueue( rast->empty_scenes, scene );
+ rast->curr_scene = NULL;
+}
+
+
+/**
+ * Rasterize commands for a single bin.
+ * \param x, y position of the bin's tile in the framebuffer
+ * Must be called between lp_rast_begin() and lp_rast_end().
+ * Called per thread.
+ */
+static void
+rasterize_bin( struct lp_rasterizer *rast,
+ unsigned thread_index,
+ const struct cmd_bin *bin,
+ int x, int y)
+{
+ const struct cmd_block_list *commands = &bin->commands;
+ struct cmd_block *block;
+ unsigned k;
+
+ lp_rast_start_tile( rast, thread_index, x, y );
+
+ /* simply execute each of the commands in the block list */
+ for (block = commands->head; block; block = block->next) {
+ for (k = 0; k < block->count; k++) {
+ block->cmd[k]( rast, thread_index, block->arg[k] );
+ }
+ }
+
+ lp_rast_end_tile( rast, thread_index );
+}
+
+
+/**
+ * Rasterize/execute all bins within a scene.
+ * Called per thread.
+ */
+static void
+rasterize_scene( struct lp_rasterizer *rast,
+ unsigned thread_index,
+ struct lp_scene *scene,
+ bool write_depth )
+{
+ /* loop over scene bins, rasterize each */
+#if 0
+ {
+ unsigned i, j;
+ for (i = 0; i < scene->tiles_x; i++) {
+ for (j = 0; j < scene->tiles_y; j++) {
+ struct cmd_bin *bin = lp_get_bin(scene, i, j);
+ rasterize_bin( rast, thread_index,
+ bin, i * TILE_SIZE, j * TILE_SIZE );
+ }
+ }
+ }
+#else
+ {
+ struct cmd_bin *bin;
+ int x, y;
+
+ assert(scene);
+ while ((bin = lp_scene_bin_iter_next(scene, &x, &y))) {
+ rasterize_bin( rast, thread_index, bin, x * TILE_SIZE, y * TILE_SIZE);
+ }
+ }
+#endif
+}
+
+
+/**
+ * Called by setup module when it has something for us to render.
+ */
+void
+lp_rasterize_scene( struct lp_rasterizer *rast,
+ struct lp_scene *scene,
+ const struct pipe_framebuffer_state *fb,
+ bool write_depth )
+{
+ boolean debug = false;
+
+ LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__);
+
+ if (debug) {
+ unsigned x, y;
+ printf("rasterize scene:\n");
+ printf(" data size: %u\n", lp_scene_data_size(scene));
+ for (y = 0; y < scene->tiles_y; y++) {
+ for (x = 0; x < scene->tiles_x; x++) {
+ printf(" bin %u, %u size: %u\n", x, y,
+ lp_scene_bin_size(scene, x, y));
+ }
+ }
+ }
+
+ /* save framebuffer state in the bin */
+ util_copy_framebuffer_state(&scene->fb, fb);
+ scene->write_depth = write_depth;
+
+ if (rast->num_threads == 0) {
+ /* no threading */
+
+ lp_rast_begin( rast, fb,
+ fb->cbufs[0]!= NULL,
+ fb->zsbuf != NULL && write_depth );
+
+ lp_scene_bin_iter_begin( scene );
+ rasterize_scene( rast, 0, scene, write_depth );
+
+ release_scene( rast, scene );
+
+ lp_rast_end( rast );
+ }
+ else {
+ /* threaded rendering! */
+ unsigned i;
+
+ lp_scene_enqueue( rast->full_scenes, scene );
+
+ /* signal the threads that there's work to do */
+ for (i = 0; i < rast->num_threads; i++) {
+ pipe_semaphore_signal(&rast->tasks[i].work_ready);
+ }
+
+ /* wait for work to complete */
+ for (i = 0; i < rast->num_threads; i++) {
+ pipe_semaphore_wait(&rast->tasks[i].work_done);
+ }
+ }
+
+ LP_DBG(DEBUG_SETUP, "%s done \n", __FUNCTION__);
+}
+
+
+/**
+ * This is the thread's main entrypoint.
+ * It's a simple loop:
+ * 1. wait for work
+ * 2. do work
+ * 3. signal that we're done
+ */
+static void *
+thread_func( void *init_data )
+{
+ struct lp_rasterizer_task *task = (struct lp_rasterizer_task *) init_data;
+ struct lp_rasterizer *rast = task->rast;
+ boolean debug = false;
+
+ while (1) {
+ /* wait for work */
+ if (debug)
+ debug_printf("thread %d waiting for work\n", task->thread_index);
+ pipe_semaphore_wait(&task->work_ready);
+
+ if (task->thread_index == 0) {
+ /* thread[0]:
+ * - get next scene to rasterize
+ * - map the framebuffer surfaces
+ */
+ const struct pipe_framebuffer_state *fb;
+ boolean write_depth;
+
+ rast->curr_scene = lp_scene_dequeue( rast->full_scenes );
+
+ lp_scene_bin_iter_begin( rast->curr_scene );
+
+ fb = &rast->curr_scene->fb;
+ write_depth = rast->curr_scene->write_depth;
+
+ lp_rast_begin( rast, fb,
+ fb->cbufs[0] != NULL,
+ fb->zsbuf != NULL && write_depth );
+ }
+
+ /* Wait for all threads to get here so that threads[1+] don't
+ * get a null rast->curr_scene pointer.
+ */
+ pipe_barrier_wait( &rast->barrier );
+
+ /* do work */
+ if (debug)
+ debug_printf("thread %d doing work\n", task->thread_index);
+ rasterize_scene(rast,
+ task->thread_index,
+ rast->curr_scene,
+ rast->curr_scene->write_depth);
+
+ /* wait for all threads to finish with this scene */
+ pipe_barrier_wait( &rast->barrier );
+
+ if (task->thread_index == 0) {
+ /* thread[0]:
+ * - release the scene object
+ * - unmap the framebuffer surfaces
+ */
+ release_scene( rast, rast->curr_scene );
+ lp_rast_end( rast );
+ }
+
+ /* signal done with work */
+ if (debug)
+ debug_printf("thread %d done working\n", task->thread_index);
+ pipe_semaphore_signal(&task->work_done);
+ }
+
+ return NULL;
+}
+
+
+/**
+ * Initialize semaphores and spawn the threads.
+ */
+static void
+create_rast_threads(struct lp_rasterizer *rast)
+{
+ unsigned i;
+
+ rast->num_threads = util_cpu_caps.nr_cpus;
+ rast->num_threads = debug_get_num_option("LP_NUM_THREADS", rast->num_threads);
+ rast->num_threads = MIN2(rast->num_threads, MAX_THREADS);
+
+ /* NOTE: if num_threads is zero, we won't use any threads */
+ for (i = 0; i < rast->num_threads; i++) {
+ pipe_semaphore_init(&rast->tasks[i].work_ready, 0);
+ pipe_semaphore_init(&rast->tasks[i].work_done, 0);
+ rast->threads[i] = pipe_thread_create(thread_func,
+ (void *) &rast->tasks[i]);
+ }
+}
+
+
+
+/**
+ * Create new lp_rasterizer.
+ * \param empty the queue to put empty scenes on after we've finished
+ * processing them.
+ */
+struct lp_rasterizer *
+lp_rast_create( struct pipe_screen *screen, struct lp_scene_queue *empty )
+{
+ struct lp_rasterizer *rast;
+ unsigned i;
+
+ rast = CALLOC_STRUCT(lp_rasterizer);
+ if(!rast)
+ return NULL;
+
+ rast->screen = screen;
+
+ rast->empty_scenes = empty;
+ rast->full_scenes = lp_scene_queue_create();
+
+ for (i = 0; i < Elements(rast->tasks); i++) {
+ rast->tasks[i].tile.color = align_malloc( TILE_SIZE*TILE_SIZE*4, 16 );
+ rast->tasks[i].tile.depth = align_malloc( TILE_SIZE*TILE_SIZE*4, 16 );
+ rast->tasks[i].rast = rast;
+ rast->tasks[i].thread_index = i;
+ }
+
+ create_rast_threads(rast);
+
+ /* for synchronizing rasterization threads */
+ pipe_barrier_init( &rast->barrier, rast->num_threads );
+
+ return rast;
+}
+
+
+/* Shutdown:
+ */
+void lp_rast_destroy( struct lp_rasterizer *rast )
+{
+ unsigned i;
+
+ util_unreference_framebuffer_state(&rast->state.fb);
+
+ for (i = 0; i < Elements(rast->tasks); i++) {
+ align_free(rast->tasks[i].tile.depth);
+ align_free(rast->tasks[i].tile.color);
+ }
+
+ /* for synchronizing rasterization threads */
+ pipe_barrier_destroy( &rast->barrier );
+
+ FREE(rast);
+}
+
+
+/** Return number of rasterization threads */
+unsigned
+lp_rast_get_num_threads( struct lp_rasterizer *rast )
+{
+ return rast->num_threads;
+}
diff --git a/src/gallium/drivers/llvmpipe/lp_rast.h b/src/gallium/drivers/llvmpipe/lp_rast.h
new file mode 100644
index 0000000000..46e22f69a6
--- /dev/null
+++ b/src/gallium/drivers/llvmpipe/lp_rast.h
@@ -0,0 +1,238 @@
+/**************************************************************************
+ *
+ * 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.
+ *
+ **************************************************************************/
+
+/**
+ * The rast code is concerned with rasterization of command bins.
+ * Each screen tile has a bin associated with it. To render the
+ * scene we iterate over the tile bins and execute the commands
+ * in each bin.
+ * We'll do that with multiple threads...
+ */
+
+
+#ifndef LP_RAST_H
+#define LP_RAST_H
+
+#include "pipe/p_compiler.h"
+#include "lp_jit.h"
+
+
+struct lp_rasterizer;
+struct lp_scene;
+struct lp_scene_queue;
+struct lp_fence;
+struct cmd_bin;
+struct pipe_screen;
+
+/** For sub-pixel positioning */
+#define FIXED_ORDER 4
+#define FIXED_ONE (1<<FIXED_ORDER)
+
+
+/**
+ * Rasterization state.
+ * Objects of this type are put into the shared data bin and pointed
+ * to by commands in the per-tile bins.
+ */
+struct lp_rast_state {
+ /* State for the shader. This also contains state which feeds into
+ * the fragment shader, such as blend color and alpha ref value.
+ */
+ struct lp_jit_context jit_context;
+
+ /* The shader itself. Probably we also need to pass a pointer to
+ * the tile color/z/stencil data somehow:
+ */
+ lp_jit_frag_func jit_function;
+};
+
+
+/**
+ * Coefficients necessary to run the shader at a given location.
+ * First coefficient is position.
+ * These pointers point into the bin data buffer.
+ */
+struct lp_rast_shader_inputs {
+ float (*a0)[4];
+ float (*dadx)[4];
+ float (*dady)[4];
+
+ /* edge/step info for 3 edges and 4x4 block of pixels */
+ int ALIGN16_ATTRIB step[3][16];
+};
+
+
+/**
+ * Rasterization information for a triangle known to be in this bin,
+ * plus inputs to run the shader:
+ * These fields are tile- and bin-independent.
+ * Objects of this type are put into the setup_context::data buffer.
+ */
+struct lp_rast_triangle {
+ /* bounding box of tri (in pixels) */
+ int minx;
+ int maxx;
+ int miny;
+ int maxy;
+
+ /* one-pixel sized trivial accept offsets for each plane */
+ int ei1;
+ int ei2;
+ int ei3;
+
+ /* one-pixel sized trivial reject offsets for each plane */
+ int eo1;
+ int eo2;
+ int eo3;
+
+ /* y deltas for vertex pairs (in fixed pt) */
+ int dy12;
+ int dy23;
+ int dy31;
+
+ /* x deltas for vertex pairs (in fixed pt) */
+ int dx12;
+ int dx23;
+ int dx31;
+
+ /* edge function values at minx,miny ?? */
+ int c1, c2, c3;
+
+ /* inputs for the shader */
+ struct lp_rast_shader_inputs ALIGN16_ATTRIB inputs;
+};
+
+
+
+struct lp_rasterizer *lp_rast_create( struct pipe_screen *screen,
+ struct lp_scene_queue *empty );
+
+void lp_rast_destroy( struct lp_rasterizer * );
+
+unsigned lp_rast_get_num_threads( struct lp_rasterizer * );
+
+void lp_rasterize_scene( struct lp_rasterizer *rast,
+ struct lp_scene *scene,
+ const struct pipe_framebuffer_state *fb,
+ bool write_depth );
+
+
+
+union lp_rast_cmd_arg {
+ const struct lp_rast_shader_inputs *shade_tile;
+ const struct lp_rast_triangle *triangle;
+ const struct lp_rast_state *set_state;
+ uint8_t clear_color[4];
+ unsigned clear_zstencil;
+ struct lp_fence *fence;
+};
+
+
+/* Cast wrappers. Hopefully these compile to noops!
+ */
+static INLINE const union lp_rast_cmd_arg
+lp_rast_arg_inputs( const struct lp_rast_shader_inputs *shade_tile )
+{
+ union lp_rast_cmd_arg arg;
+ arg.shade_tile = shade_tile;
+ return arg;
+}
+
+static INLINE const union lp_rast_cmd_arg
+lp_rast_arg_triangle( const struct lp_rast_triangle *triangle )
+{
+ union lp_rast_cmd_arg arg;
+ arg.triangle = triangle;
+ return arg;
+}
+
+static INLINE const union lp_rast_cmd_arg
+lp_rast_arg_state( const struct lp_rast_state *state )
+{
+ union lp_rast_cmd_arg arg;
+ arg.set_state = state;
+ return arg;
+}
+
+static INLINE const union lp_rast_cmd_arg
+lp_rast_arg_fence( struct lp_fence *fence )
+{
+ union lp_rast_cmd_arg arg;
+ arg.fence = fence;
+ return arg;
+}
+
+
+static INLINE const union lp_rast_cmd_arg
+lp_rast_arg_null( void )
+{
+ union lp_rast_cmd_arg arg;
+ arg.set_state = NULL;
+ return arg;
+}
+
+
+
+/**
+ * Binnable Commands.
+ * These get put into bins by the setup code and are called when
+ * the bins are executed.
+ */
+
+void lp_rast_clear_color( struct lp_rasterizer *,
+ unsigned thread_index,
+ const union lp_rast_cmd_arg );
+
+void lp_rast_clear_zstencil( struct lp_rasterizer *,
+ unsigned thread_index,
+ const union lp_rast_cmd_arg );
+
+void lp_rast_load_color( struct lp_rasterizer *,
+ unsigned thread_index,
+ const union lp_rast_cmd_arg );
+
+void lp_rast_load_zstencil( struct lp_rasterizer *,
+ unsigned thread_index,
+ const union lp_rast_cmd_arg );
+
+void lp_rast_set_state( struct lp_rasterizer *,
+ unsigned thread_index,
+ const union lp_rast_cmd_arg );
+
+void lp_rast_triangle( struct lp_rasterizer *,
+ unsigned thread_index,
+ const union lp_rast_cmd_arg );
+
+void lp_rast_shade_tile( struct lp_rasterizer *,
+ unsigned thread_index,
+ const union lp_rast_cmd_arg );
+
+void lp_rast_fence( struct lp_rasterizer *,
+ unsigned thread_index,
+ const union lp_rast_cmd_arg );
+
+#endif
diff --git a/src/gallium/drivers/llvmpipe/lp_rast_priv.h b/src/gallium/drivers/llvmpipe/lp_rast_priv.h
new file mode 100644
index 0000000000..cd72d7e69d
--- /dev/null
+++ b/src/gallium/drivers/llvmpipe/lp_rast_priv.h
@@ -0,0 +1,129 @@
+/**************************************************************************
+ *
+ * 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 LP_RAST_PRIV_H
+#define LP_RAST_PRIV_H
+
+#include "pipe/p_thread.h"
+#include "lp_rast.h"
+
+
+#define MAX_THREADS 8 /* XXX probably temporary here */
+
+
+struct pipe_transfer;
+struct pipe_screen;
+struct lp_rasterizer;
+
+
+/**
+ * A tile's color and depth memory.
+ * We can choose whatever layout for the internal tile storage we prefer.
+ */
+struct lp_rast_tile
+{
+ uint8_t *color;
+
+ uint32_t *depth;
+};
+
+
+/**
+ * Per-thread rasterization state
+ */
+struct lp_rasterizer_task
+{
+ struct lp_rast_tile tile; /** Tile color/z/stencil memory */
+
+ unsigned x, y; /**< Pos of this tile in framebuffer, in pixels */
+
+ const struct lp_rast_state *current_state;
+
+ /** "back" pointer */
+ struct lp_rasterizer *rast;
+
+ /** "my" index */
+ unsigned thread_index;
+
+ pipe_semaphore work_ready;
+ pipe_semaphore work_done;
+};
+
+
+/**
+ * This is the state required while rasterizing tiles.
+ * Note that this contains per-thread information too.
+ * The tile size is TILE_SIZE x TILE_SIZE pixels.
+ */
+struct lp_rasterizer
+{
+ boolean clipped_tile;
+ boolean check_for_clipped_tiles;
+
+ /* Framebuffer stuff
+ */
+ struct pipe_screen *screen;
+ struct pipe_transfer *cbuf_transfer;
+ struct pipe_transfer *zsbuf_transfer;
+ void *cbuf_map;
+ void *zsbuf_map;
+
+ struct {
+ struct pipe_framebuffer_state fb;
+ boolean write_color;
+ boolean write_zstencil;
+ unsigned clear_color;
+ unsigned clear_depth;
+ char clear_stencil;
+ } state;
+
+ /** The incoming queue of scenes ready to rasterize */
+ struct lp_scene_queue *full_scenes;
+ /** The outgoing queue of processed scenes to return to setup modulee */
+ struct lp_scene_queue *empty_scenes;
+
+ /** The scene currently being rasterized by the threads */
+ struct lp_scene *curr_scene;
+
+ /** A task object for each rasterization thread */
+ struct lp_rasterizer_task tasks[MAX_THREADS];
+
+ unsigned num_threads;
+ pipe_thread threads[MAX_THREADS];
+
+ /** For synchronizing the rasterization threads */
+ pipe_barrier barrier;
+};
+
+
+void lp_rast_shade_quads( struct lp_rasterizer *rast,
+ unsigned thread_index,
+ const struct lp_rast_shader_inputs *inputs,
+ unsigned x, unsigned y,
+ int32_t c1, int32_t c2, int32_t c3);
+
+#endif
diff --git a/src/gallium/drivers/llvmpipe/lp_rast_tri.c b/src/gallium/drivers/llvmpipe/lp_rast_tri.c
new file mode 100644
index 0000000000..bc7397f50c
--- /dev/null
+++ b/src/gallium/drivers/llvmpipe/lp_rast_tri.c
@@ -0,0 +1,253 @@
+/**************************************************************************
+ *
+ * Copyright 2007-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.
+ *
+ **************************************************************************/
+
+/*
+ * Rasterization for binned triangles within a tile
+ */
+
+#include <limits.h>
+#include "util/u_math.h"
+#include "lp_debug.h"
+#include "lp_rast_priv.h"
+#include "lp_tile_soa.h"
+
+
+/**
+ * Map an index in [0,15] to an x,y position, multiplied by 4.
+ * This is used to get the position of each subtile in a 4x4
+ * grid of edge step values.
+ */
+static const int pos_table4[16][2] = {
+ { 0, 0 },
+ { 4, 0 },
+ { 0, 4 },
+ { 4, 4 },
+ { 8, 0 },
+ { 12, 0 },
+ { 8, 4 },
+ { 12, 4 },
+ { 0, 8 },
+ { 4, 8 },
+ { 0, 12 },
+ { 4, 12 },
+ { 8, 8 },
+ { 12, 8 },
+ { 8, 12 },
+ { 12, 12 }
+};
+
+
+static const int pos_table16[16][2] = {
+ { 0, 0 },
+ { 16, 0 },
+ { 0, 16 },
+ { 16, 16 },
+ { 32, 0 },
+ { 48, 0 },
+ { 32, 16 },
+ { 48, 16 },
+ { 0, 32 },
+ { 16, 32 },
+ { 0, 48 },
+ { 16, 48 },
+ { 32, 32 },
+ { 48, 32 },
+ { 32, 48 },
+ { 48, 48 }
+};
+
+
+/**
+ * Shade all pixels in a 4x4 block.
+ */
+static void
+block_full_4( struct lp_rasterizer_task *rast_task,
+ const struct lp_rast_triangle *tri,
+ int x, int y )
+{
+ /* Set c1,c2,c3 to large values so the in/out test always passes */
+ const int32_t c1 = INT_MIN, c2 = INT_MIN, c3 = INT_MIN;
+ lp_rast_shade_quads(rast_task->rast,
+ rast_task->thread_index,
+ &tri->inputs,
+ x, y,
+ c1, c2, c3);
+}
+
+
+/**
+ * Shade all pixels in a 16x16 block.
+ */
+static void
+block_full_16( struct lp_rasterizer_task *rast_task,
+ const struct lp_rast_triangle *tri,
+ int x, int y )
+{
+ unsigned ix, iy;
+ assert(x % 16 == 0);
+ assert(y % 16 == 0);
+ for (iy = 0; iy < 16; iy += 4)
+ for (ix = 0; ix < 16; ix += 4)
+ block_full_4(rast_task, tri, x + ix, y + iy);
+}
+
+
+/**
+ * Pass the 4x4 pixel block to the shader function.
+ * Determination of which of the 16 pixels lies inside the triangle
+ * will be done as part of the fragment shader.
+ */
+static void
+do_block_4( struct lp_rasterizer_task *rast_task,
+ const struct lp_rast_triangle *tri,
+ int x, int y,
+ int c1,
+ int c2,
+ int c3 )
+{
+ lp_rast_shade_quads(rast_task->rast,
+ rast_task->thread_index,
+ &tri->inputs,
+ x, y,
+ -c1, -c2, -c3);
+}
+
+
+/**
+ * Evaluate a 16x16 block of pixels to determine which 4x4 subblocks are in/out
+ * of the triangle's bounds.
+ */
+static void
+do_block_16( struct lp_rasterizer_task *rast_task,
+ const struct lp_rast_triangle *tri,
+ int x, int y,
+ int c1,
+ int c2,
+ int c3 )
+{
+ const int ei1 = tri->ei1 * 4;
+ const int ei2 = tri->ei2 * 4;
+ const int ei3 = tri->ei3 * 4;
+
+ const int eo1 = tri->eo1 * 4;
+ const int eo2 = tri->eo2 * 4;
+ const int eo3 = tri->eo3 * 4;
+
+ int i;
+
+ assert(x % 16 == 0);
+ assert(y % 16 == 0);
+
+ for (i = 0; i < 16; i++) {
+ int cx1 = c1 + (tri->inputs.step[0][i] * 4);
+ int cx2 = c2 + (tri->inputs.step[1][i] * 4);
+ int cx3 = c3 + (tri->inputs.step[2][i] * 4);
+
+ if (cx1 + eo1 < 0 ||
+ cx2 + eo2 < 0 ||
+ cx3 + eo3 < 0) {
+ /* the block is completely outside the triangle - nop */
+ }
+ else {
+ int px = x + pos_table4[i][0];
+ int py = y + pos_table4[i][1];
+ if (cx1 + ei1 > 0 &&
+ cx2 + ei2 > 0 &&
+ cx3 + ei3 > 0) {
+ /* the block is completely inside the triangle */
+ block_full_4(rast_task, tri, px, py);
+ }
+ else {
+ /* the block is partially in/out of the triangle */
+ do_block_4(rast_task, tri, px, py, cx1, cx2, cx3);
+ }
+ }
+ }
+}
+
+
+/**
+ * Scan the tile in chunks and figure out which pixels to rasterize
+ * for this triangle.
+ */
+void
+lp_rast_triangle( struct lp_rasterizer *rast,
+ unsigned thread_index,
+ const union lp_rast_cmd_arg arg )
+{
+ struct lp_rasterizer_task *rast_task = &rast->tasks[thread_index];
+ const struct lp_rast_triangle *tri = arg.triangle;
+
+ int x = rast_task->x;
+ int y = rast_task->y;
+ unsigned i;
+
+ int c1 = tri->c1 + tri->dx12 * y - tri->dy12 * x;
+ int c2 = tri->c2 + tri->dx23 * y - tri->dy23 * x;
+ int c3 = tri->c3 + tri->dx31 * y - tri->dy31 * x;
+
+ int ei1 = tri->ei1 * 16;
+ int ei2 = tri->ei2 * 16;
+ int ei3 = tri->ei3 * 16;
+
+ int eo1 = tri->eo1 * 16;
+ int eo2 = tri->eo2 * 16;
+ int eo3 = tri->eo3 * 16;
+
+ LP_DBG(DEBUG_RAST, "lp_rast_triangle\n");
+
+ /* Walk over the tile to build a list of 4x4 pixel blocks which will
+ * be filled/shaded. We do this at two granularities: 16x16 blocks
+ * and then 4x4 blocks.
+ */
+ for (i = 0; i < 16; i++) {
+ int cx1 = c1 + (tri->inputs.step[0][i] * 16);
+ int cx2 = c2 + (tri->inputs.step[1][i] * 16);
+ int cx3 = c3 + (tri->inputs.step[2][i] * 16);
+
+ if (cx1 + eo1 < 0 ||
+ cx2 + eo2 < 0 ||
+ cx3 + eo3 < 0) {
+ /* the block is completely outside the triangle - nop */
+ }
+ else {
+ int px = x + pos_table16[i][0];
+ int py = y + pos_table16[i][1];
+
+ if (cx1 + ei1 > 0 &&
+ cx2 + ei2 > 0 &&
+ cx3 + ei3 > 0) {
+ /* the block is completely inside the triangle */
+ block_full_16(rast_task, tri, px, py);
+ }
+ else {
+ /* the block is partially in/out of the triangle */
+ do_block_16(rast_task, tri, px, py, cx1, cx2, cx3);
+ }
+ }
+ }
+}
diff --git a/src/gallium/drivers/llvmpipe/lp_scene.c b/src/gallium/drivers/llvmpipe/lp_scene.c
new file mode 100644
index 0000000000..774a1fecd7
--- /dev/null
+++ b/src/gallium/drivers/llvmpipe/lp_scene.c
@@ -0,0 +1,310 @@
+/**************************************************************************
+ *
+ * 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.
+ *
+ **************************************************************************/
+
+#include "util/u_math.h"
+#include "util/u_memory.h"
+#include "lp_scene.h"
+
+
+struct lp_scene *
+lp_scene_create(void)
+{
+ struct lp_scene *scene = CALLOC_STRUCT(lp_scene);
+ if (scene)
+ lp_scene_init(scene);
+ return scene;
+}
+
+
+void
+lp_scene_destroy(struct lp_scene *scene)
+{
+ lp_scene_reset(scene);
+ lp_scene_free_bin_data(scene);
+ FREE(scene);
+}
+
+
+void
+lp_scene_init(struct lp_scene *scene)
+{
+ unsigned i, j;
+ for (i = 0; i < TILES_X; i++)
+ for (j = 0; j < TILES_Y; j++) {
+ struct cmd_bin *bin = lp_scene_get_bin(scene, i, j);
+ bin->commands.head = bin->commands.tail = CALLOC_STRUCT(cmd_block);
+ }
+
+ scene->data.head =
+ scene->data.tail = CALLOC_STRUCT(data_block);
+
+ pipe_mutex_init(scene->mutex);
+}
+
+
+/**
+ * Set scene to empty state.
+ */
+void
+lp_scene_reset(struct lp_scene *scene )
+{
+ unsigned i, j;
+
+ /* Free all but last binner command lists:
+ */
+ for (i = 0; i < scene->tiles_x; i++) {
+ for (j = 0; j < scene->tiles_y; j++) {
+ struct cmd_bin *bin = lp_scene_get_bin(scene, i, j);
+ struct cmd_block_list *list = &bin->commands;
+ struct cmd_block *block;
+ struct cmd_block *tmp;
+
+ for (block = list->head; block != list->tail; block = tmp) {
+ tmp = block->next;
+ FREE(block);
+ }
+
+ assert(list->tail->next == NULL);
+ list->head = list->tail;
+ list->head->count = 0;
+ }
+ }
+
+ /* Free all but last binned data block:
+ */
+ {
+ struct data_block_list *list = &scene->data;
+ struct data_block *block, *tmp;
+
+ for (block = list->head; block != list->tail; block = tmp) {
+ tmp = block->next;
+ FREE(block);
+ }
+
+ assert(list->tail->next == NULL);
+ list->head = list->tail;
+ list->head->used = 0;
+ }
+}
+
+
+/**
+ * Free all data associated with the given bin, but don't free(scene).
+ */
+void
+lp_scene_free_bin_data(struct lp_scene *scene)
+{
+ unsigned i, j;
+
+ for (i = 0; i < TILES_X; i++)
+ for (j = 0; j < TILES_Y; j++) {
+ struct cmd_bin *bin = lp_scene_get_bin(scene, i, j);
+ /* lp_reset_scene() should have been already called */
+ assert(bin->commands.head == bin->commands.tail);
+ FREE(bin->commands.head);
+ bin->commands.head = NULL;
+ bin->commands.tail = NULL;
+ }
+
+ FREE(scene->data.head);
+ scene->data.head = NULL;
+
+ pipe_mutex_destroy(scene->mutex);
+}
+
+
+void
+lp_scene_set_framebuffer_size( struct lp_scene *scene,
+ unsigned width, unsigned height )
+{
+ scene->tiles_x = align(width, TILE_SIZE) / TILE_SIZE;
+ scene->tiles_y = align(height, TILE_SIZE) / TILE_SIZE;
+}
+
+
+void
+lp_bin_new_cmd_block( struct cmd_block_list *list )
+{
+ struct cmd_block *block = MALLOC_STRUCT(cmd_block);
+ list->tail->next = block;
+ list->tail = block;
+ block->next = NULL;
+ block->count = 0;
+}
+
+
+void
+lp_bin_new_data_block( struct data_block_list *list )
+{
+ struct data_block *block = MALLOC_STRUCT(data_block);
+ list->tail->next = block;
+ list->tail = block;
+ block->next = NULL;
+ block->used = 0;
+}
+
+
+/** Return number of bytes used for all bin data within a scene */
+unsigned
+lp_scene_data_size( const struct lp_scene *scene )
+{
+ unsigned size = 0;
+ const struct data_block *block;
+ for (block = scene->data.head; block; block = block->next) {
+ size += block->used;
+ }
+ return size;
+}
+
+
+/** Return number of bytes used for a single bin */
+unsigned
+lp_scene_bin_size( const struct lp_scene *scene, unsigned x, unsigned y )
+{
+ struct cmd_bin *bin = lp_scene_get_bin((struct lp_scene *) scene, x, y);
+ const struct cmd_block *cmd;
+ unsigned size = 0;
+ for (cmd = bin->commands.head; cmd; cmd = cmd->next) {
+ size += (cmd->count *
+ (sizeof(lp_rast_cmd) + sizeof(union lp_rast_cmd_arg)));
+ }
+ return size;
+}
+
+
+/**
+ * Return last command in the bin
+ */
+static lp_rast_cmd
+lp_get_last_command( const struct cmd_bin *bin )
+{
+ const struct cmd_block *tail = bin->commands.tail;
+ const unsigned i = tail->count;
+ if (i > 0)
+ return tail->cmd[i - 1];
+ else
+ return NULL;
+}
+
+
+/**
+ * Replace the arg of the last command in the bin.
+ */
+static void
+lp_replace_last_command_arg( struct cmd_bin *bin,
+ const union lp_rast_cmd_arg arg )
+{
+ struct cmd_block *tail = bin->commands.tail;
+ const unsigned i = tail->count;
+ assert(i > 0);
+ tail->arg[i - 1] = arg;
+}
+
+
+
+/**
+ * Put a state-change command into all bins.
+ * If we find that the last command in a bin was also a state-change
+ * command, we can simply replace that one with the new one.
+ */
+void
+lp_scene_bin_state_command( struct lp_scene *scene,
+ lp_rast_cmd cmd,
+ const union lp_rast_cmd_arg arg )
+{
+ unsigned i, j;
+ for (i = 0; i < scene->tiles_x; i++) {
+ for (j = 0; j < scene->tiles_y; j++) {
+ struct cmd_bin *bin = lp_scene_get_bin(scene, i, j);
+ lp_rast_cmd last_cmd = lp_get_last_command(bin);
+ if (last_cmd == cmd) {
+ lp_replace_last_command_arg(bin, arg);
+ }
+ else {
+ lp_scene_bin_command( scene, i, j, cmd, arg );
+ }
+ }
+ }
+}
+
+
+/** advance curr_x,y to the next bin */
+static boolean
+next_bin(struct lp_scene *scene)
+{
+ scene->curr_x++;
+ if (scene->curr_x >= scene->tiles_x) {
+ scene->curr_x = 0;
+ scene->curr_y++;
+ }
+ if (scene->curr_y >= scene->tiles_y) {
+ /* no more bins */
+ return FALSE;
+ }
+ return TRUE;
+}
+
+
+void
+lp_scene_bin_iter_begin( struct lp_scene *scene )
+{
+ scene->curr_x = scene->curr_y = -1;
+}
+
+
+/**
+ * Return point to next bin to be rendered.
+ * The lp_scene::curr_x and ::curr_y fields will be advanced.
+ * Multiple rendering threads will call this function to get a chunk
+ * of work (a bin) to work on.
+ */
+struct cmd_bin *
+lp_scene_bin_iter_next( struct lp_scene *scene, int *bin_x, int *bin_y )
+{
+ struct cmd_bin *bin = NULL;
+
+ pipe_mutex_lock(scene->mutex);
+
+ if (scene->curr_x < 0) {
+ /* first bin */
+ scene->curr_x = 0;
+ scene->curr_y = 0;
+ }
+ else if (!next_bin(scene)) {
+ /* no more bins left */
+ goto end;
+ }
+
+ bin = lp_scene_get_bin(scene, scene->curr_x, scene->curr_y);
+ *bin_x = scene->curr_x;
+ *bin_y = scene->curr_y;
+
+end:
+ /*printf("return bin %p at %d, %d\n", (void *) bin, *bin_x, *bin_y);*/
+ pipe_mutex_unlock(scene->mutex);
+ return bin;
+}
diff --git a/src/gallium/drivers/llvmpipe/lp_scene.h b/src/gallium/drivers/llvmpipe/lp_scene.h
new file mode 100644
index 0000000000..796fc516cc
--- /dev/null
+++ b/src/gallium/drivers/llvmpipe/lp_scene.h
@@ -0,0 +1,276 @@
+/**************************************************************************
+ *
+ * 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.
+ *
+ **************************************************************************/
+
+
+/**
+ * Binner data structures and bin-related functions.
+ * Note: the "setup" code is concerned with building scenes while
+ * The "rast" code is concerned with consuming/executing scenes.
+ */
+
+#ifndef LP_SCENE_H
+#define LP_SCENE_H
+
+#include "pipe/p_thread.h"
+#include "lp_tile_soa.h"
+#include "lp_rast.h"
+
+
+/* We're limited to 2K by 2K for 32bit fixed point rasterization.
+ * Will need a 64-bit version for larger framebuffers.
+ */
+#define MAXHEIGHT 2048
+#define MAXWIDTH 2048
+#define TILES_X (MAXWIDTH / TILE_SIZE)
+#define TILES_Y (MAXHEIGHT / TILE_SIZE)
+
+
+#define CMD_BLOCK_MAX 128
+#define DATA_BLOCK_SIZE (16 * 1024 - sizeof(unsigned) - sizeof(void *))
+
+
+
+/* switch to a non-pointer value for this:
+ */
+typedef void (*lp_rast_cmd)( struct lp_rasterizer *,
+ unsigned thread_index,
+ const union lp_rast_cmd_arg );
+
+struct cmd_block {
+ lp_rast_cmd cmd[CMD_BLOCK_MAX];
+ union lp_rast_cmd_arg arg[CMD_BLOCK_MAX];
+ unsigned count;
+ struct cmd_block *next;
+};
+
+struct data_block {
+ ubyte data[DATA_BLOCK_SIZE];
+ unsigned used;
+ struct data_block *next;
+};
+
+struct cmd_block_list {
+ struct cmd_block *head;
+ struct cmd_block *tail;
+};
+
+/**
+ * For each screen tile we have one of these bins.
+ */
+struct cmd_bin {
+ struct cmd_block_list commands;
+};
+
+
+/**
+ * This stores bulk data which is shared by all bins within a scene.
+ * Examples include triangle data and state data. The commands in
+ * the per-tile bins will point to chunks of data in this structure.
+ */
+struct data_block_list {
+ struct data_block *head;
+ struct data_block *tail;
+};
+
+
+/**
+ * All bins and bin data are contained here.
+ * Per-bin data goes into the 'tile' bins.
+ * Shared data goes into the 'data' buffer.
+ *
+ * When there are multiple threads, will want to double-buffer between
+ * scenes:
+ */
+struct lp_scene {
+ struct cmd_bin tile[TILES_X][TILES_Y];
+ struct data_block_list data;
+
+ /** the framebuffer to render the scene into */
+ struct pipe_framebuffer_state fb;
+
+ boolean write_depth;
+
+ /**
+ * Number of active tiles in each dimension.
+ * This basically the framebuffer size divided by tile size
+ */
+ unsigned tiles_x, tiles_y;
+
+ int curr_x, curr_y; /**< for iterating over bins */
+ pipe_mutex mutex;
+};
+
+
+
+struct lp_scene *lp_scene_create(void);
+
+void lp_scene_destroy(struct lp_scene *scene);
+
+
+void lp_scene_init(struct lp_scene *scene);
+
+void lp_scene_reset(struct lp_scene *scene );
+
+void lp_scene_free_bin_data(struct lp_scene *scene);
+
+void lp_scene_set_framebuffer_size( struct lp_scene *scene,
+ unsigned width, unsigned height );
+
+void lp_bin_new_data_block( struct data_block_list *list );
+
+void lp_bin_new_cmd_block( struct cmd_block_list *list );
+
+unsigned lp_scene_data_size( const struct lp_scene *scene );
+
+unsigned lp_scene_bin_size( const struct lp_scene *scene, unsigned x, unsigned y );
+
+
+/**
+ * Allocate space for a command/data in the bin's data buffer.
+ * Grow the block list if needed.
+ */
+static INLINE void *
+lp_scene_alloc( struct lp_scene *scene, unsigned size)
+{
+ struct data_block_list *list = &scene->data;
+
+ if (list->tail->used + size > DATA_BLOCK_SIZE) {
+ lp_bin_new_data_block( list );
+ }
+
+ {
+ struct data_block *tail = list->tail;
+ ubyte *data = tail->data + tail->used;
+ tail->used += size;
+ return data;
+ }
+}
+
+
+/**
+ * As above, but with specific alignment.
+ */
+static INLINE void *
+lp_scene_alloc_aligned( struct lp_scene *scene, unsigned size,
+ unsigned alignment )
+{
+ struct data_block_list *list = &scene->data;
+
+ if (list->tail->used + size + alignment - 1 > DATA_BLOCK_SIZE) {
+ lp_bin_new_data_block( list );
+ }
+
+ {
+ struct data_block *tail = list->tail;
+ ubyte *data = tail->data + tail->used;
+ unsigned offset = (((uintptr_t)data + alignment - 1) & ~(alignment - 1)) - (uintptr_t)data;
+ tail->used += offset + size;
+ return data + offset;
+ }
+}
+
+
+/* Put back data if we decide not to use it, eg. culled triangles.
+ */
+static INLINE void
+lp_scene_putback_data( struct lp_scene *scene, unsigned size)
+{
+ struct data_block_list *list = &scene->data;
+ assert(list->tail->used >= size);
+ list->tail->used -= size;
+}
+
+
+/** Return pointer to a particular tile's bin. */
+static INLINE struct cmd_bin *
+lp_scene_get_bin(struct lp_scene *scene, unsigned x, unsigned y)
+{
+ return &scene->tile[x][y];
+}
+
+
+
+/* Add a command to bin[x][y].
+ */
+static INLINE void
+lp_scene_bin_command( struct lp_scene *scene,
+ unsigned x, unsigned y,
+ lp_rast_cmd cmd,
+ union lp_rast_cmd_arg arg )
+{
+ struct cmd_bin *bin = lp_scene_get_bin(scene, x, y);
+ struct cmd_block_list *list = &bin->commands;
+
+ if (list->tail->count == CMD_BLOCK_MAX) {
+ lp_bin_new_cmd_block( list );
+ }
+
+ {
+ struct cmd_block *tail = list->tail;
+ unsigned i = tail->count;
+ tail->cmd[i] = cmd;
+ tail->arg[i] = arg;
+ tail->count++;
+ }
+}
+
+
+/* Add a command to all active bins.
+ */
+static INLINE void
+lp_scene_bin_everywhere( struct lp_scene *scene,
+ lp_rast_cmd cmd,
+ const union lp_rast_cmd_arg arg )
+{
+ unsigned i, j;
+ for (i = 0; i < scene->tiles_x; i++)
+ for (j = 0; j < scene->tiles_y; j++)
+ lp_scene_bin_command( scene, i, j, cmd, arg );
+}
+
+
+void
+lp_scene_bin_state_command( struct lp_scene *scene,
+ lp_rast_cmd cmd,
+ const union lp_rast_cmd_arg arg );
+
+
+static INLINE unsigned
+lp_scene_get_num_bins( const struct lp_scene *scene )
+{
+ return scene->tiles_x * scene->tiles_y;
+}
+
+
+void
+lp_scene_bin_iter_begin( struct lp_scene *scene );
+
+struct cmd_bin *
+lp_scene_bin_iter_next( struct lp_scene *scene, int *bin_x, int *bin_y );
+
+
+#endif /* LP_BIN_H */
diff --git a/src/gallium/drivers/llvmpipe/lp_scene_queue.c b/src/gallium/drivers/llvmpipe/lp_scene_queue.c
new file mode 100644
index 0000000000..8d65a6a6fa
--- /dev/null
+++ b/src/gallium/drivers/llvmpipe/lp_scene_queue.c
@@ -0,0 +1,164 @@
+/**************************************************************************
+ *
+ * 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.
+ *
+ **************************************************************************/
+
+
+/**
+ * Scene queue. We'll use two queues. One contains "full" scenes which
+ * are produced by the "setup" code. The other contains "empty" scenes
+ * which are produced by the "rast" code when it finishes rendering a scene.
+ */
+
+
+#include "pipe/p_thread.h"
+#include "util/u_memory.h"
+#include "lp_scene_queue.h"
+
+
+
+#define MAX_SCENE_QUEUE 4
+
+
+/**
+ * A queue of scenes
+ */
+struct lp_scene_queue
+{
+ /** XXX might use a linked list here somedone, but the list will
+ * probably always be pretty short.
+ */
+ struct lp_scene *scenes[MAX_SCENE_QUEUE];
+ unsigned count;
+
+ pipe_condvar count_change;
+ pipe_mutex mutex;
+};
+
+
+
+/** Allocate a new scene queue */
+struct lp_scene_queue *
+lp_scene_queue_create(void)
+{
+ struct lp_scene_queue *queue = CALLOC_STRUCT(lp_scene_queue);
+ if (queue) {
+ pipe_condvar_init(queue->count_change);
+ pipe_mutex_init(queue->mutex);
+ }
+ return queue;
+}
+
+
+/** Delete a scene queue */
+void
+lp_scene_queue_destroy(struct lp_scene_queue *queue)
+{
+ pipe_condvar_destroy(queue->count_change);
+ pipe_mutex_destroy(queue->mutex);
+}
+
+
+/** Remove first lp_scene from head of queue */
+struct lp_scene *
+lp_scene_dequeue(struct lp_scene_queue *queue)
+{
+ struct lp_scene *scene;
+ unsigned i;
+
+ pipe_mutex_lock(queue->mutex);
+ while (queue->count == 0) {
+ pipe_condvar_wait(queue->count_change, queue->mutex);
+ }
+
+ assert(queue->count >= 1);
+
+ /* get head */
+ scene = queue->scenes[0];
+
+ /* shift entries */
+ for (i = 0; i < queue->count - 1; i++) {
+ queue->scenes[i] = queue->scenes[i + 1];
+ }
+
+ queue->count--;
+
+ /* signal size change */
+ pipe_condvar_signal(queue->count_change);
+
+ pipe_mutex_unlock(queue->mutex);
+
+ return scene;
+}
+
+
+/** Add an lp_scene to tail of queue */
+void
+lp_scene_enqueue(struct lp_scene_queue *queue, struct lp_scene *scene)
+{
+ pipe_mutex_lock(queue->mutex);
+
+ assert(queue->count < MAX_SCENE_QUEUE);
+
+ /* debug: check that scene is not already in the queue */
+ if (0) {
+ unsigned i;
+ for (i = 0; i < queue->count; i++) {
+ assert(queue->scenes[i] != scene);
+ }
+ }
+
+ /* add to end */
+ queue->scenes[queue->count++] = scene;
+
+ /* signal size change */
+ pipe_condvar_signal(queue->count_change);
+
+ pipe_mutex_unlock(queue->mutex);
+}
+
+
+/** Return number of entries in the queue */
+unsigned
+lp_scene_queue_count(struct lp_scene_queue *queue)
+{
+ unsigned count;
+ pipe_mutex_lock(queue->mutex);
+ count = queue->count;
+ pipe_mutex_unlock(queue->mutex);
+ return count;
+}
+
+
+/** Wait until the queue has exactly 'count' entries */
+void
+lp_scene_queue_wait_count(struct lp_scene_queue *queue, unsigned count)
+{
+ pipe_mutex_lock(queue->mutex);
+ while (queue->count != count) {
+ pipe_condvar_wait(queue->count_change, queue->mutex);
+ }
+ pipe_mutex_unlock(queue->mutex);
+}
diff --git a/src/gallium/drivers/llvmpipe/lp_scene_queue.h b/src/gallium/drivers/llvmpipe/lp_scene_queue.h
new file mode 100644
index 0000000000..1bd475fa50
--- /dev/null
+++ b/src/gallium/drivers/llvmpipe/lp_scene_queue.h
@@ -0,0 +1,55 @@
+/**************************************************************************
+ *
+ * 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 LP_SCENE_QUEUE
+#define LP_SCENE_QUEUE
+
+struct lp_scene_queue;
+struct lp_scene;
+
+
+struct lp_scene_queue *
+lp_scene_queue_create(void);
+
+void
+lp_scene_queue_destroy(struct lp_scene_queue *queue);
+
+struct lp_scene *
+lp_scene_dequeue(struct lp_scene_queue *queue);
+
+void
+lp_scene_enqueue(struct lp_scene_queue *queue, struct lp_scene *bins);
+
+unsigned
+lp_scene_queue_count(struct lp_scene_queue *queue);
+
+void
+lp_scene_queue_wait_count(struct lp_scene_queue *queue, unsigned size);
+
+
+#endif /* LP_BIN_QUEUE */
diff --git a/src/gallium/drivers/llvmpipe/lp_screen.c b/src/gallium/drivers/llvmpipe/lp_screen.c
index 9b47415f00..a28f6935b6 100644
--- a/src/gallium/drivers/llvmpipe/lp_screen.c
+++ b/src/gallium/drivers/llvmpipe/lp_screen.c
@@ -33,6 +33,7 @@
#include "lp_texture.h"
#include "lp_buffer.h"
+#include "lp_fence.h"
#include "lp_winsys.h"
#include "lp_jit.h"
#include "lp_screen.h"
@@ -299,6 +300,7 @@ llvmpipe_create_screen(struct llvmpipe_winsys *winsys)
llvmpipe_init_screen_texture_funcs(&screen->base);
llvmpipe_init_screen_buffer_funcs(&screen->base);
+ llvmpipe_init_screen_fence_funcs(&screen->base);
lp_jit_screen_init(screen);
diff --git a/src/gallium/drivers/llvmpipe/lp_setup.c b/src/gallium/drivers/llvmpipe/lp_setup.c
index b18f17c0cd..5cdcf4ecc9 100644
--- a/src/gallium/drivers/llvmpipe/lp_setup.c
+++ b/src/gallium/drivers/llvmpipe/lp_setup.c
@@ -26,1479 +26,631 @@
**************************************************************************/
/**
- * \brief Primitive rasterization/rendering (points, lines, triangles)
+ * Tiling engine.
*
- * \author Keith Whitwell <keith@tungstengraphics.com>
- * \author Brian Paul
+ * Builds per-tile display lists and executes them on calls to
+ * lp_setup_flush().
*/
-#include "lp_context.h"
-#include "lp_quad.h"
-#include "lp_setup.h"
-#include "lp_state.h"
-#include "draw/draw_context.h"
-#include "draw/draw_private.h"
-#include "draw/draw_vertex.h"
-#include "pipe/p_shader_tokens.h"
-#include "pipe/p_thread.h"
-#include "util/u_format.h"
-#include "util/u_math.h"
+#include "pipe/p_defines.h"
+#include "pipe/p_inlines.h"
#include "util/u_memory.h"
-#include "lp_bld_debug.h"
-#include "lp_tile_cache.h"
-#include "lp_tile_soa.h"
-
-
-#define DEBUG_VERTS 0
-#define DEBUG_FRAGS 0
-
-/**
- * Triangle edge info
- */
-struct edge {
- float dx; /**< X(v1) - X(v0), used only during setup */
- float dy; /**< Y(v1) - Y(v0), used only during setup */
- float dxdy; /**< dx/dy */
- float sx, sy; /**< first sample point coord */
- int lines; /**< number of lines on this edge */
-};
-
-
-#define MAX_QUADS 16
-
-
-/**
- * Triangle setup info (derived from draw_stage).
- * Also used for line drawing (taking some liberties).
- */
-struct setup_context {
- struct llvmpipe_context *llvmpipe;
-
- /* Vertices are just an array of floats making up each attribute in
- * turn. Currently fixed at 4 floats, but should change in time.
- * Codegen will help cope with this.
- */
- const float (*vmax)[4];
- const float (*vmid)[4];
- const float (*vmin)[4];
- const float (*vprovoke)[4];
-
- struct edge ebot;
- struct edge etop;
- struct edge emaj;
-
- float oneoverarea;
- int facing;
-
- float pixel_offset;
-
- struct quad_header quad[MAX_QUADS];
- struct quad_header *quad_ptrs[MAX_QUADS];
- unsigned count;
+#include "util/u_pack_color.h"
+#include "util/u_surface.h"
+#include "lp_scene.h"
+#include "lp_scene_queue.h"
+#include "lp_buffer.h"
+#include "lp_texture.h"
+#include "lp_debug.h"
+#include "lp_fence.h"
+#include "lp_rast.h"
+#include "lp_setup_context.h"
- struct quad_interp_coef coef;
+#include "draw/draw_context.h"
+#include "draw/draw_vbuf.h"
- struct {
- int left[2]; /**< [0] = row0, [1] = row1 */
- int right[2];
- int y;
- } span;
-#if DEBUG_FRAGS
- uint numFragsEmitted; /**< per primitive */
- uint numFragsWritten; /**< per primitive */
-#endif
+/** XXX temporary value, temporary here */
+#define MAX_SCENES 2
- unsigned winding; /* which winding to cull */
-};
+static void set_scene_state( struct setup_context *, unsigned );
-/**
- * Execute fragment shader for the four fragments in the quad.
- */
-ALIGN_STACK
-static void
-shade_quads(struct llvmpipe_context *llvmpipe,
- struct quad_header *quads[],
- unsigned nr)
+struct lp_scene *
+lp_setup_get_current_scene(struct setup_context *setup)
{
- struct lp_fragment_shader *fs = llvmpipe->fs;
- struct quad_header *quad = quads[0];
- const unsigned x = quad->input.x0;
- const unsigned y = quad->input.y0;
- uint8_t *tile;
- uint8_t *color;
- void *depth;
- uint32_t ALIGN16_ATTRIB mask[4][NUM_CHANNELS];
- unsigned chan_index;
- unsigned q;
-
- assert(fs->current);
- if(!fs->current)
- return;
+ if (!setup->scene) {
+ /* wait for a free/empty bin */
+ setup->scene = lp_scene_dequeue(setup->empty_scenes);
+ if(0)lp_scene_reset( setup->scene ); /* XXX temporary? */
- /* Sanity checks */
- assert(nr * QUAD_SIZE == TILE_VECTOR_HEIGHT * TILE_VECTOR_WIDTH);
- assert(x % TILE_VECTOR_WIDTH == 0);
- assert(y % TILE_VECTOR_HEIGHT == 0);
- for (q = 0; q < nr; ++q) {
- assert(quads[q]->input.x0 == x + q*2);
- assert(quads[q]->input.y0 == y);
- }
-
- /* mask */
- for (q = 0; q < 4; ++q)
- for (chan_index = 0; chan_index < NUM_CHANNELS; ++chan_index)
- mask[q][chan_index] = quads[q]->inout.mask & (1 << chan_index) ? ~0 : 0;
-
- /* color buffer */
- if(llvmpipe->framebuffer.nr_cbufs >= 1 &&
- llvmpipe->framebuffer.cbufs[0]) {
- tile = lp_get_cached_tile(llvmpipe->cbuf_cache[0], x, y);
- color = &TILE_PIXEL(tile, x & (TILE_SIZE-1), y & (TILE_SIZE-1), 0);
- }
- else
- color = NULL;
-
- /* depth buffer */
- if(llvmpipe->zsbuf_map) {
- assert((x % 2) == 0);
- assert((y % 2) == 0);
- depth = llvmpipe->zsbuf_map +
- y*llvmpipe->zsbuf_transfer->stride +
- 2*x*util_format_get_blocksize(llvmpipe->zsbuf_transfer->texture->format);
+ lp_scene_set_framebuffer_size(setup->scene,
+ setup->fb.width,
+ setup->fb.height);
}
- else
- depth = NULL;
-
- /* XXX: This will most likely fail on 32bit x86 without -mstackrealign */
- assert(lp_check_alignment(mask, 16));
-
- assert(lp_check_alignment(depth, 16));
- assert(lp_check_alignment(color, 16));
- assert(lp_check_alignment(llvmpipe->jit_context.blend_color, 16));
-
- /* run shader */
- fs->current->jit_function( &llvmpipe->jit_context,
- x, y,
- quad->coef->a0,
- quad->coef->dadx,
- quad->coef->dady,
- &mask[0][0],
- color,
- depth);
+ return setup->scene;
}
-
-
-/**
- * Do triangle cull test using tri determinant (sign indicates orientation)
- * \return true if triangle is to be culled.
- */
-static INLINE boolean
-cull_tri(const struct setup_context *setup, float det)
+static void
+first_triangle( struct setup_context *setup,
+ const float (*v0)[4],
+ const float (*v1)[4],
+ const float (*v2)[4])
{
- if (det != 0) {
- /* if (det < 0 then Z points toward camera and triangle is
- * counter-clockwise winding.
- */
- unsigned winding = (det < 0) ? PIPE_WINDING_CCW : PIPE_WINDING_CW;
-
- if ((winding & setup->winding) == 0)
- return FALSE;
- }
-
- /* Culled:
- */
- return TRUE;
+ set_scene_state( setup, SETUP_ACTIVE );
+ lp_setup_choose_triangle( setup );
+ setup->triangle( setup, v0, v1, v2 );
}
-
-
-/**
- * Clip setup->quad against the scissor/surface bounds.
- */
-static INLINE void
-quad_clip( struct setup_context *setup, struct quad_header *quad )
+static void
+first_line( struct setup_context *setup,
+ const float (*v0)[4],
+ const float (*v1)[4])
{
- const struct pipe_scissor_state *cliprect = &setup->llvmpipe->cliprect;
- const int minx = (int) cliprect->minx;
- const int maxx = (int) cliprect->maxx;
- const int miny = (int) cliprect->miny;
- const int maxy = (int) cliprect->maxy;
-
- if (quad->input.x0 >= maxx ||
- quad->input.y0 >= maxy ||
- quad->input.x0 + 1 < minx ||
- quad->input.y0 + 1 < miny) {
- /* totally clipped */
- quad->inout.mask = 0x0;
- return;
- }
- if (quad->input.x0 < minx)
- quad->inout.mask &= (MASK_BOTTOM_RIGHT | MASK_TOP_RIGHT);
- if (quad->input.y0 < miny)
- quad->inout.mask &= (MASK_BOTTOM_LEFT | MASK_BOTTOM_RIGHT);
- if (quad->input.x0 == maxx - 1)
- quad->inout.mask &= (MASK_BOTTOM_LEFT | MASK_TOP_LEFT);
- if (quad->input.y0 == maxy - 1)
- quad->inout.mask &= (MASK_TOP_LEFT | MASK_TOP_RIGHT);
+ set_scene_state( setup, SETUP_ACTIVE );
+ lp_setup_choose_line( setup );
+ setup->line( setup, v0, v1 );
}
-
-
-/**
- * Given an X or Y coordinate, return the block/quad coordinate that it
- * belongs to.
- */
-static INLINE int block( int x )
+static void
+first_point( struct setup_context *setup,
+ const float (*v0)[4])
{
- return x & ~(2-1);
+ set_scene_state( setup, SETUP_ACTIVE );
+ lp_setup_choose_point( setup );
+ setup->point( setup, v0 );
}
-static INLINE int block_x( int x )
+static void reset_context( struct setup_context *setup )
{
- return x & ~(TILE_VECTOR_WIDTH - 1);
-}
+ LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__);
+ /* Reset derived state */
+ setup->constants.stored_size = 0;
+ setup->constants.stored_data = NULL;
+ setup->fs.stored = NULL;
+ setup->dirty = ~0;
-/**
- * Emit a quad (pass to next stage) with clipping.
- */
-static INLINE void
-clip_emit_quad( struct setup_context *setup, struct quad_header *quad )
-{
- quad_clip( setup, quad );
-
- if (quad->inout.mask) {
- struct llvmpipe_context *lp = setup->llvmpipe;
-
-#if 1
- /* XXX: The blender expects 4 quads. This is far from efficient, but
- * until we codegenerate single-quad variants of the fragment pipeline
- * we need this hack. */
- const unsigned nr_quads = TILE_VECTOR_HEIGHT*TILE_VECTOR_WIDTH/QUAD_SIZE;
- struct quad_header quads[4];
- struct quad_header *quad_ptrs[4];
- int x0 = block_x(quad->input.x0);
- unsigned i;
-
- assert(nr_quads == 4);
-
- for(i = 0; i < nr_quads; ++i) {
- int x = x0 + 2*i;
- if(x == quad->input.x0)
- memcpy(&quads[i], quad, sizeof quads[i]);
- else {
- memset(&quads[i], 0, sizeof quads[i]);
- quads[i].input.x0 = x;
- quads[i].input.y0 = quad->input.y0;
- quads[i].coef = quad->coef;
- }
- quad_ptrs[i] = &quads[i];
- }
+ /* no current bin */
+ setup->scene = NULL;
- shade_quads( lp, quad_ptrs, nr_quads );
-#else
- shade_quads( lp, &quad, 1 );
-#endif
- }
+ /* Reset some state:
+ */
+ setup->clear.flags = 0;
+
+ /* Have an explicit "start-binning" call and get rid of this
+ * pointer twiddling?
+ */
+ setup->line = first_line;
+ setup->point = first_point;
+ setup->triangle = first_triangle;
}
-/**
- * Render a horizontal span of quads
- */
-static void flush_spans( struct setup_context *setup )
+/** Rasterize all scene's bins */
+static void
+lp_setup_rasterize_scene( struct setup_context *setup,
+ boolean write_depth )
{
- const int step = TILE_VECTOR_WIDTH;
- const int xleft0 = setup->span.left[0];
- const int xleft1 = setup->span.left[1];
- const int xright0 = setup->span.right[0];
- const int xright1 = setup->span.right[1];
-
-
- int minleft = block_x(MIN2(xleft0, xleft1));
- int maxright = MAX2(xright0, xright1);
- int x;
-
- for (x = minleft; x < maxright; x += step) {
- unsigned skip_left0 = CLAMP(xleft0 - x, 0, step);
- unsigned skip_left1 = CLAMP(xleft1 - x, 0, step);
- unsigned skip_right0 = CLAMP(x + step - xright0, 0, step);
- unsigned skip_right1 = CLAMP(x + step - xright1, 0, step);
- unsigned lx = x;
- const unsigned nr_quads = TILE_VECTOR_HEIGHT*TILE_VECTOR_WIDTH/QUAD_SIZE;
- unsigned q = 0;
-
- unsigned skipmask_left0 = (1U << skip_left0) - 1U;
- unsigned skipmask_left1 = (1U << skip_left1) - 1U;
-
- /* These calculations fail when step == 32 and skip_right == 0.
- */
- unsigned skipmask_right0 = ~0U << (unsigned)(step - skip_right0);
- unsigned skipmask_right1 = ~0U << (unsigned)(step - skip_right1);
-
- unsigned mask0 = ~skipmask_left0 & ~skipmask_right0;
- unsigned mask1 = ~skipmask_left1 & ~skipmask_right1;
-
- if (mask0 | mask1) {
- for(q = 0; q < nr_quads; ++q) {
- unsigned quadmask = (mask0 & 3) | ((mask1 & 3) << 2);
- setup->quad[q].input.x0 = lx;
- setup->quad[q].input.y0 = setup->span.y;
- setup->quad[q].inout.mask = quadmask;
- setup->quad_ptrs[q] = &setup->quad[q];
- mask0 >>= 2;
- mask1 >>= 2;
- lx += 2;
- }
- assert(!(mask0 | mask1));
+ struct lp_scene *scene = lp_setup_get_current_scene(setup);
- shade_quads(setup->llvmpipe, setup->quad_ptrs, nr_quads );
- }
- }
+ lp_rasterize_scene(setup->rast,
+ scene,
+ &setup->fb,
+ write_depth);
+ reset_context( setup );
- setup->span.y = 0;
- setup->span.right[0] = 0;
- setup->span.right[1] = 0;
- setup->span.left[0] = 1000000; /* greater than right[0] */
- setup->span.left[1] = 1000000; /* greater than right[1] */
+ LP_DBG(DEBUG_SETUP, "%s done \n", __FUNCTION__);
}
-#if DEBUG_VERTS
-static void print_vertex(const struct setup_context *setup,
- const float (*v)[4])
-{
- int i;
- debug_printf(" Vertex: (%p)\n", v);
- for (i = 0; i < setup->quad[0].nr_attrs; i++) {
- debug_printf(" %d: %f %f %f %f\n", i,
- v[i][0], v[i][1], v[i][2], v[i][3]);
- if (util_is_inf_or_nan(v[i][0])) {
- debug_printf(" NaN!\n");
- }
- }
-}
-#endif
-/**
- * Sort the vertices from top to bottom order, setting up the triangle
- * edge fields (ebot, emaj, etop).
- * \return FALSE if coords are inf/nan (cull the tri), TRUE otherwise
- */
-static boolean setup_sort_vertices( struct setup_context *setup,
- float det,
- const float (*v0)[4],
- const float (*v1)[4],
- const float (*v2)[4] )
+static void
+begin_binning( struct setup_context *setup )
{
- setup->vprovoke = v2;
-
- /* determine bottom to top order of vertices */
- {
- float y0 = v0[0][1];
- float y1 = v1[0][1];
- float y2 = v2[0][1];
- if (y0 <= y1) {
- if (y1 <= y2) {
- /* y0<=y1<=y2 */
- setup->vmin = v0;
- setup->vmid = v1;
- setup->vmax = v2;
- }
- else if (y2 <= y0) {
- /* y2<=y0<=y1 */
- setup->vmin = v2;
- setup->vmid = v0;
- setup->vmax = v1;
- }
- else {
- /* y0<=y2<=y1 */
- setup->vmin = v0;
- setup->vmid = v2;
- setup->vmax = v1;
- }
- }
- else {
- if (y0 <= y2) {
- /* y1<=y0<=y2 */
- setup->vmin = v1;
- setup->vmid = v0;
- setup->vmax = v2;
- }
- else if (y2 <= y1) {
- /* y2<=y1<=y0 */
- setup->vmin = v2;
- setup->vmid = v1;
- setup->vmax = v0;
- }
- else {
- /* y1<=y2<=y0 */
- setup->vmin = v1;
- setup->vmid = v2;
- setup->vmax = v0;
- }
- }
- }
-
- setup->ebot.dx = setup->vmid[0][0] - setup->vmin[0][0];
- setup->ebot.dy = setup->vmid[0][1] - setup->vmin[0][1];
- setup->emaj.dx = setup->vmax[0][0] - setup->vmin[0][0];
- setup->emaj.dy = setup->vmax[0][1] - setup->vmin[0][1];
- setup->etop.dx = setup->vmax[0][0] - setup->vmid[0][0];
- setup->etop.dy = setup->vmax[0][1] - setup->vmid[0][1];
-
- /*
- * Compute triangle's area. Use 1/area to compute partial
- * derivatives of attributes later.
- *
- * The area will be the same as prim->det, but the sign may be
- * different depending on how the vertices get sorted above.
- *
- * To determine whether the primitive is front or back facing we
- * use the prim->det value because its sign is correct.
- */
- {
- const float area = (setup->emaj.dx * setup->ebot.dy -
- setup->ebot.dx * setup->emaj.dy);
-
- setup->oneoverarea = 1.0f / area;
-
- /*
- debug_printf("%s one-over-area %f area %f det %f\n",
- __FUNCTION__, setup->oneoverarea, area, det );
- */
- if (util_is_inf_or_nan(setup->oneoverarea))
- return FALSE;
- }
+ struct lp_scene *scene = lp_setup_get_current_scene(setup);
- /* We need to know if this is a front or back-facing triangle for:
- * - the GLSL gl_FrontFacing fragment attribute (bool)
- * - two-sided stencil test
- */
- setup->facing =
- ((det > 0.0) ^
- (setup->llvmpipe->rasterizer->front_winding == PIPE_WINDING_CW));
+ LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__);
- /* Prepare pixel offset for rasterisation:
- * - pixel center (0.5, 0.5) for GL, or
- * - assume (0.0, 0.0) for other APIs.
- */
- if (setup->llvmpipe->rasterizer->gl_rasterization_rules) {
- setup->pixel_offset = 0.5f;
- } else {
- setup->pixel_offset = 0.0f;
+ if (setup->fb.cbufs[0]) {
+ if (setup->clear.flags & PIPE_CLEAR_COLOR)
+ lp_scene_bin_everywhere( scene,
+ lp_rast_clear_color,
+ setup->clear.color );
+ else
+ lp_scene_bin_everywhere( scene,
+ lp_rast_load_color,
+ lp_rast_arg_null() );
}
- return TRUE;
-}
-
+ if (setup->fb.zsbuf) {
+ if (setup->clear.flags & PIPE_CLEAR_DEPTHSTENCIL)
+ lp_scene_bin_everywhere( scene,
+ lp_rast_clear_zstencil,
+ setup->clear.zstencil );
+ else
+ lp_scene_bin_everywhere( scene,
+ lp_rast_load_zstencil,
+ lp_rast_arg_null() );
+ }
-/**
- * Compute a0, dadx and dady for a linearly interpolated coefficient,
- * for a triangle.
- */
-static void tri_pos_coeff( struct setup_context *setup,
- uint vertSlot, unsigned i)
-{
- float botda = setup->vmid[vertSlot][i] - setup->vmin[vertSlot][i];
- float majda = setup->vmax[vertSlot][i] - setup->vmin[vertSlot][i];
- float a = setup->ebot.dy * majda - botda * setup->emaj.dy;
- float b = setup->emaj.dx * botda - majda * setup->ebot.dx;
- float dadx = a * setup->oneoverarea;
- float dady = b * setup->oneoverarea;
-
- assert(i <= 3);
-
- setup->coef.dadx[0][i] = dadx;
- setup->coef.dady[0][i] = dady;
-
- /* calculate a0 as the value which would be sampled for the
- * fragment at (0,0), taking into account that we want to sample at
- * pixel centers, in other words (pixel_offset, pixel_offset).
- *
- * this is neat but unfortunately not a good way to do things for
- * triangles with very large values of dadx or dady as it will
- * result in the subtraction and re-addition from a0 of a very
- * large number, which means we'll end up loosing a lot of the
- * fractional bits and precision from a0. the way to fix this is
- * to define a0 as the sample at a pixel center somewhere near vmin
- * instead - i'll switch to this later.
- */
- setup->coef.a0[0][i] = (setup->vmin[vertSlot][i] -
- (dadx * (setup->vmin[0][0] - setup->pixel_offset) +
- dady * (setup->vmin[0][1] - setup->pixel_offset)));
-
- /*
- debug_printf("attr[%d].%c: %f dx:%f dy:%f\n",
- slot, "xyzw"[i],
- setup->coef[slot].a0[i],
- setup->coef[slot].dadx[i],
- setup->coef[slot].dady[i]);
- */
+ LP_DBG(DEBUG_SETUP, "%s done\n", __FUNCTION__);
}
-/**
- * Compute a0 for a constant-valued coefficient (GL_FLAT shading).
- * The value value comes from vertex[slot][i].
- * The result will be put into setup->coef[slot].a0[i].
- * \param slot which attribute slot
- * \param i which component of the slot (0..3)
+/* This basically bins and then flushes any outstanding full-screen
+ * clears.
+ *
+ * TODO: fast path for fullscreen clears and no triangles.
*/
-static void const_pos_coeff( struct setup_context *setup,
- uint vertSlot, unsigned i)
+static void
+execute_clears( struct setup_context *setup )
{
- setup->coef.dadx[0][i] = 0;
- setup->coef.dady[0][i] = 0;
+ LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__);
- /* need provoking vertex info!
- */
- setup->coef.a0[0][i] = setup->vprovoke[vertSlot][i];
+ begin_binning( setup );
+ lp_setup_rasterize_scene( setup, TRUE );
}
-/**
- * Compute a0 for a constant-valued coefficient (GL_FLAT shading).
- * The value value comes from vertex[slot][i].
- * The result will be put into setup->coef[slot].a0[i].
- * \param slot which attribute slot
- * \param i which component of the slot (0..3)
- */
-static void const_coeff( struct setup_context *setup,
- unsigned attrib,
- uint vertSlot)
+static void
+set_scene_state( struct setup_context *setup,
+ unsigned new_state )
{
- unsigned i;
- for (i = 0; i < NUM_CHANNELS; ++i) {
- setup->coef.dadx[1 + attrib][i] = 0;
- setup->coef.dady[1 + attrib][i] = 0;
+ unsigned old_state = setup->state;
- /* need provoking vertex info!
- */
- setup->coef.a0[1 + attrib][i] = setup->vprovoke[vertSlot][i];
- }
-}
+ if (old_state == new_state)
+ return;
+
+ LP_DBG(DEBUG_SETUP, "%s old %d new %d\n", __FUNCTION__, old_state, new_state);
+ switch (new_state) {
+ case SETUP_ACTIVE:
+ begin_binning( setup );
+ break;
-/**
- * Compute a0, dadx and dady for a linearly interpolated coefficient,
- * for a triangle.
- */
-static void tri_linear_coeff( struct setup_context *setup,
- unsigned attrib,
- uint vertSlot)
-{
- unsigned i;
- for (i = 0; i < NUM_CHANNELS; ++i) {
- float botda = setup->vmid[vertSlot][i] - setup->vmin[vertSlot][i];
- float majda = setup->vmax[vertSlot][i] - setup->vmin[vertSlot][i];
- float a = setup->ebot.dy * majda - botda * setup->emaj.dy;
- float b = setup->emaj.dx * botda - majda * setup->ebot.dx;
- float dadx = a * setup->oneoverarea;
- float dady = b * setup->oneoverarea;
-
- assert(i <= 3);
-
- setup->coef.dadx[1 + attrib][i] = dadx;
- setup->coef.dady[1 + attrib][i] = dady;
-
- /* calculate a0 as the value which would be sampled for the
- * fragment at (0,0), taking into account that we want to sample at
- * pixel centers, in other words (0.5, 0.5).
- *
- * this is neat but unfortunately not a good way to do things for
- * triangles with very large values of dadx or dady as it will
- * result in the subtraction and re-addition from a0 of a very
- * large number, which means we'll end up loosing a lot of the
- * fractional bits and precision from a0. the way to fix this is
- * to define a0 as the sample at a pixel center somewhere near vmin
- * instead - i'll switch to this later.
- */
- setup->coef.a0[1 + attrib][i] = (setup->vmin[vertSlot][i] -
- (dadx * (setup->vmin[0][0] - setup->pixel_offset) +
- dady * (setup->vmin[0][1] - setup->pixel_offset)));
-
- /*
- debug_printf("attr[%d].%c: %f dx:%f dy:%f\n",
- slot, "xyzw"[i],
- setup->coef[slot].a0[i],
- setup->coef[slot].dadx[i],
- setup->coef[slot].dady[i]);
- */
+ case SETUP_CLEARED:
+ if (old_state == SETUP_ACTIVE) {
+ assert(0);
+ return;
+ }
+ break;
+
+ case SETUP_FLUSHED:
+ if (old_state == SETUP_CLEARED)
+ execute_clears( setup );
+ else
+ lp_setup_rasterize_scene( setup, TRUE );
+ break;
}
-}
-
-/**
- * Compute a0, dadx and dady for a perspective-corrected interpolant,
- * for a triangle.
- * We basically multiply the vertex value by 1/w before computing
- * the plane coefficients (a0, dadx, dady).
- * Later, when we compute the value at a particular fragment position we'll
- * divide the interpolated value by the interpolated W at that fragment.
- */
-static void tri_persp_coeff( struct setup_context *setup,
- unsigned attrib,
- uint vertSlot)
-{
- unsigned i;
- for (i = 0; i < NUM_CHANNELS; ++i) {
- /* premultiply by 1/w (v[0][3] is always W):
- */
- float mina = setup->vmin[vertSlot][i] * setup->vmin[0][3];
- float mida = setup->vmid[vertSlot][i] * setup->vmid[0][3];
- float maxa = setup->vmax[vertSlot][i] * setup->vmax[0][3];
- float botda = mida - mina;
- float majda = maxa - mina;
- float a = setup->ebot.dy * majda - botda * setup->emaj.dy;
- float b = setup->emaj.dx * botda - majda * setup->ebot.dx;
- float dadx = a * setup->oneoverarea;
- float dady = b * setup->oneoverarea;
-
- /*
- debug_printf("tri persp %d,%d: %f %f %f\n", vertSlot, i,
- setup->vmin[vertSlot][i],
- setup->vmid[vertSlot][i],
- setup->vmax[vertSlot][i]
- );
- */
- assert(i <= 3);
-
- setup->coef.dadx[1 + attrib][i] = dadx;
- setup->coef.dady[1 + attrib][i] = dady;
- setup->coef.a0[1 + attrib][i] = (mina -
- (dadx * (setup->vmin[0][0] - setup->pixel_offset) +
- dady * (setup->vmin[0][1] - setup->pixel_offset)));
- }
+ setup->state = new_state;
}
-/**
- * Special coefficient setup for gl_FragCoord.
- * X and Y are trivial, though Y has to be inverted for OpenGL.
- * Z and W are copied from posCoef which should have already been computed.
- * We could do a bit less work if we'd examine gl_FragCoord's swizzle mask.
- */
-static void
-setup_fragcoord_coeff(struct setup_context *setup, uint slot)
+void
+lp_setup_flush( struct setup_context *setup,
+ unsigned flags )
{
- /*X*/
- setup->coef.a0[1 + slot][0] = 0;
- setup->coef.dadx[1 + slot][0] = 1.0;
- setup->coef.dady[1 + slot][0] = 0.0;
- /*Y*/
- setup->coef.a0[1 + slot][1] = 0.0;
- setup->coef.dadx[1 + slot][1] = 0.0;
- setup->coef.dady[1 + slot][1] = 1.0;
- /*Z*/
- setup->coef.a0[1 + slot][2] = setup->coef.a0[0][2];
- setup->coef.dadx[1 + slot][2] = setup->coef.dadx[0][2];
- setup->coef.dady[1 + slot][2] = setup->coef.dady[0][2];
- /*W*/
- setup->coef.a0[1 + slot][3] = setup->coef.a0[0][3];
- setup->coef.dadx[1 + slot][3] = setup->coef.dadx[0][3];
- setup->coef.dady[1 + slot][3] = setup->coef.dady[0][3];
-}
+ LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__);
+ set_scene_state( setup, SETUP_FLUSHED );
+}
-/**
- * Compute the setup->coef[] array dadx, dady, a0 values.
- * Must be called after setup->vmin,vmid,vmax,vprovoke are initialized.
- */
-static void setup_tri_coefficients( struct setup_context *setup )
+void
+lp_setup_bind_framebuffer( struct setup_context *setup,
+ const struct pipe_framebuffer_state *fb )
{
- struct llvmpipe_context *llvmpipe = setup->llvmpipe;
- const struct lp_fragment_shader *lpfs = llvmpipe->fs;
- const struct vertex_info *vinfo = llvmpipe_get_vertex_info(llvmpipe);
- uint fragSlot;
+ struct lp_scene *scene = lp_setup_get_current_scene(setup);
- /* z and w are done by linear interpolation:
- */
- tri_pos_coeff(setup, 0, 2);
- tri_pos_coeff(setup, 0, 3);
+ LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__);
- /* setup interpolation for all the remaining attributes:
- */
- for (fragSlot = 0; fragSlot < lpfs->info.num_inputs; fragSlot++) {
- const uint vertSlot = vinfo->attrib[fragSlot].src_index;
+ set_scene_state( setup, SETUP_FLUSHED );
- switch (vinfo->attrib[fragSlot].interp_mode) {
- case INTERP_CONSTANT:
- const_coeff(setup, fragSlot, vertSlot);
- break;
- case INTERP_LINEAR:
- tri_linear_coeff(setup, fragSlot, vertSlot);
- break;
- case INTERP_PERSPECTIVE:
- tri_persp_coeff(setup, fragSlot, vertSlot);
- break;
- case INTERP_POS:
- setup_fragcoord_coeff(setup, fragSlot);
- break;
- default:
- assert(0);
- }
+ util_copy_framebuffer_state(&setup->fb, fb);
- if (lpfs->info.input_semantic_name[fragSlot] == TGSI_SEMANTIC_FACE) {
- setup->coef.a0[1 + fragSlot][0] = 1.0f - setup->facing;
- setup->coef.dadx[1 + fragSlot][0] = 0.0;
- setup->coef.dady[1 + fragSlot][0] = 0.0;
- }
- }
+ lp_scene_set_framebuffer_size(scene, setup->fb.width, setup->fb.height);
}
-
-static void setup_tri_edges( struct setup_context *setup )
+void
+lp_setup_clear( struct setup_context *setup,
+ const float *color,
+ double depth,
+ unsigned stencil,
+ unsigned flags )
{
- float vmin_x = setup->vmin[0][0] + setup->pixel_offset;
- float vmid_x = setup->vmid[0][0] + setup->pixel_offset;
-
- float vmin_y = setup->vmin[0][1] - setup->pixel_offset;
- float vmid_y = setup->vmid[0][1] - setup->pixel_offset;
- float vmax_y = setup->vmax[0][1] - setup->pixel_offset;
-
- setup->emaj.sy = ceilf(vmin_y);
- setup->emaj.lines = (int) ceilf(vmax_y - setup->emaj.sy);
- setup->emaj.dxdy = setup->emaj.dx / setup->emaj.dy;
- setup->emaj.sx = vmin_x + (setup->emaj.sy - vmin_y) * setup->emaj.dxdy;
-
- setup->etop.sy = ceilf(vmid_y);
- setup->etop.lines = (int) ceilf(vmax_y - setup->etop.sy);
- setup->etop.dxdy = setup->etop.dx / setup->etop.dy;
- setup->etop.sx = vmid_x + (setup->etop.sy - vmid_y) * setup->etop.dxdy;
-
- setup->ebot.sy = ceilf(vmin_y);
- setup->ebot.lines = (int) ceilf(vmid_y - setup->ebot.sy);
- setup->ebot.dxdy = setup->ebot.dx / setup->ebot.dy;
- setup->ebot.sx = vmin_x + (setup->ebot.sy - vmin_y) * setup->ebot.dxdy;
-}
+ struct lp_scene *scene = lp_setup_get_current_scene(setup);
+ unsigned i;
+ LP_DBG(DEBUG_SETUP, "%s state %d\n", __FUNCTION__, setup->state);
-/**
- * Render the upper or lower half of a triangle.
- * Scissoring/cliprect is applied here too.
- */
-static void subtriangle( struct setup_context *setup,
- struct edge *eleft,
- struct edge *eright,
- unsigned lines )
-{
- const struct pipe_scissor_state *cliprect = &setup->llvmpipe->cliprect;
- const int minx = (int) cliprect->minx;
- const int maxx = (int) cliprect->maxx;
- const int miny = (int) cliprect->miny;
- const int maxy = (int) cliprect->maxy;
- int y, start_y, finish_y;
- int sy = (int)eleft->sy;
-
- assert((int)eleft->sy == (int) eright->sy);
-
- /* clip top/bottom */
- start_y = sy;
- if (start_y < miny)
- start_y = miny;
-
- finish_y = sy + lines;
- if (finish_y > maxy)
- finish_y = maxy;
-
- start_y -= sy;
- finish_y -= sy;
-
- /*
- debug_printf("%s %d %d\n", __FUNCTION__, start_y, finish_y);
- */
-
- for (y = start_y; y < finish_y; y++) {
-
- /* avoid accumulating adds as floats don't have the precision to
- * accurately iterate large triangle edges that way. luckily we
- * can just multiply these days.
- *
- * this is all drowned out by the attribute interpolation anyway.
- */
- int left = (int)(eleft->sx + y * eleft->dxdy);
- int right = (int)(eright->sx + y * eright->dxdy);
-
- /* clip left/right */
- if (left < minx)
- left = minx;
- if (right > maxx)
- right = maxx;
-
- if (left < right) {
- int _y = sy + y;
- if (block(_y) != setup->span.y) {
- flush_spans(setup);
- setup->span.y = block(_y);
- }
- setup->span.left[_y&1] = left;
- setup->span.right[_y&1] = right;
- }
+ if (flags & PIPE_CLEAR_COLOR) {
+ for (i = 0; i < 4; ++i)
+ setup->clear.color.clear_color[i] = float_to_ubyte(color[i]);
}
+ if (flags & PIPE_CLEAR_DEPTHSTENCIL) {
+ setup->clear.zstencil.clear_zstencil =
+ util_pack_z_stencil(setup->fb.zsbuf->format,
+ depth,
+ stencil);
+ }
- /* save the values so that emaj can be restarted:
- */
- eleft->sx += lines * eleft->dxdy;
- eright->sx += lines * eright->dxdy;
- eleft->sy += lines;
- eright->sy += lines;
-}
+ if (setup->state == SETUP_ACTIVE) {
+ /* Add the clear to existing scene. In the unusual case where
+ * both color and depth-stencil are being cleared when there's
+ * already been some rendering, we could discard the currently
+ * binned scene and start again, but I don't see that as being
+ * a common usage.
+ */
+ if (flags & PIPE_CLEAR_COLOR)
+ lp_scene_bin_everywhere( scene,
+ lp_rast_clear_color,
+ setup->clear.color );
+ if (setup->clear.flags & PIPE_CLEAR_DEPTHSTENCIL)
+ lp_scene_bin_everywhere( scene,
+ lp_rast_clear_zstencil,
+ setup->clear.zstencil );
+ }
+ else {
+ /* Put ourselves into the 'pre-clear' state, specifically to try
+ * and accumulate multiple clears to color and depth_stencil
+ * buffers which the app or state-tracker might issue
+ * separately.
+ */
+ set_scene_state( setup, SETUP_CLEARED );
-/**
- * Recalculate prim's determinant. This is needed as we don't have
- * get this information through the vbuf_render interface & we must
- * calculate it here.
- */
-static float
-calc_det( const float (*v0)[4],
- const float (*v1)[4],
- const float (*v2)[4] )
-{
- /* edge vectors e = v0 - v2, f = v1 - v2 */
- const float ex = v0[0][0] - v2[0][0];
- const float ey = v0[0][1] - v2[0][1];
- const float fx = v1[0][0] - v2[0][0];
- const float fy = v1[0][1] - v2[0][1];
-
- /* det = cross(e,f).z */
- return ex * fy - ey * fx;
+ setup->clear.flags |= flags;
+ }
}
/**
- * Do setup for triangle rasterization, then render the triangle.
+ * Emit a fence.
*/
-void llvmpipe_setup_tri( struct setup_context *setup,
- const float (*v0)[4],
- const float (*v1)[4],
- const float (*v2)[4] )
+struct pipe_fence_handle *
+lp_setup_fence( struct setup_context *setup )
{
- float det;
+ struct lp_scene *scene = lp_setup_get_current_scene(setup);
+ const unsigned rank = lp_scene_get_num_bins( scene ); /* xxx */
+ struct lp_fence *fence = lp_fence_create(rank);
-#if DEBUG_VERTS
- debug_printf("Setup triangle:\n");
- print_vertex(setup, v0);
- print_vertex(setup, v1);
- print_vertex(setup, v2);
-#endif
+ LP_DBG(DEBUG_SETUP, "%s rank %u\n", __FUNCTION__, rank);
- if (setup->llvmpipe->no_rast)
- return;
-
- det = calc_det(v0, v1, v2);
- /*
- debug_printf("%s\n", __FUNCTION__ );
- */
+ set_scene_state( setup, SETUP_ACTIVE );
-#if DEBUG_FRAGS
- setup->numFragsEmitted = 0;
- setup->numFragsWritten = 0;
-#endif
+ /* insert the fence into all command bins */
+ lp_scene_bin_everywhere( scene,
+ lp_rast_fence,
+ lp_rast_arg_fence(fence) );
- if (cull_tri( setup, det ))
- return;
+ return (struct pipe_fence_handle *) fence;
+}
- if (!setup_sort_vertices( setup, det, v0, v1, v2 ))
- return;
- setup_tri_coefficients( setup );
- setup_tri_edges( setup );
- assert(setup->llvmpipe->reduced_prim == PIPE_PRIM_TRIANGLES);
+void
+lp_setup_set_triangle_state( struct setup_context *setup,
+ unsigned cull_mode,
+ boolean ccw_is_frontface)
+{
+ LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__);
- setup->span.y = 0;
- setup->span.right[0] = 0;
- setup->span.right[1] = 0;
- /* setup->span.z_mode = tri_z_mode( setup->ctx ); */
+ setup->ccw_is_frontface = ccw_is_frontface;
+ setup->cullmode = cull_mode;
+ setup->triangle = first_triangle;
+}
- /* init_constant_attribs( setup ); */
- if (setup->oneoverarea < 0.0) {
- /* emaj on left:
- */
- subtriangle( setup, &setup->emaj, &setup->ebot, setup->ebot.lines );
- subtriangle( setup, &setup->emaj, &setup->etop, setup->etop.lines );
- }
- else {
- /* emaj on right:
- */
- subtriangle( setup, &setup->ebot, &setup->emaj, setup->ebot.lines );
- subtriangle( setup, &setup->etop, &setup->emaj, setup->etop.lines );
- }
- flush_spans( setup );
+void
+lp_setup_set_fs_inputs( struct setup_context *setup,
+ const struct lp_shader_input *input,
+ unsigned nr )
+{
+ LP_DBG(DEBUG_SETUP, "%s %p %u\n", __FUNCTION__, (void *) input, nr);
-#if DEBUG_FRAGS
- printf("Tri: %u frags emitted, %u written\n",
- setup->numFragsEmitted,
- setup->numFragsWritten);
-#endif
+ memcpy( setup->fs.input, input, nr * sizeof input[0] );
+ setup->fs.nr_inputs = nr;
}
+void
+lp_setup_set_fs_function( struct setup_context *setup,
+ lp_jit_frag_func jit_function )
+{
+ LP_DBG(DEBUG_SETUP, "%s %p\n", __FUNCTION__, (void *) jit_function);
+ /* FIXME: reference count */
+ setup->fs.current.jit_function = jit_function;
+ setup->dirty |= LP_SETUP_NEW_FS;
+}
-/**
- * Compute a0, dadx and dady for a linearly interpolated coefficient,
- * for a line.
- */
-static void
-linear_pos_coeff(struct setup_context *setup,
- uint vertSlot, uint i)
+void
+lp_setup_set_fs_constants(struct setup_context *setup,
+ struct pipe_buffer *buffer)
{
- const float da = setup->vmax[vertSlot][i] - setup->vmin[vertSlot][i];
- const float dadx = da * setup->emaj.dx * setup->oneoverarea;
- const float dady = da * setup->emaj.dy * setup->oneoverarea;
- setup->coef.dadx[0][i] = dadx;
- setup->coef.dady[0][i] = dady;
- setup->coef.a0[0][i] = (setup->vmin[vertSlot][i] -
- (dadx * (setup->vmin[0][0] - setup->pixel_offset) +
- dady * (setup->vmin[0][1] - setup->pixel_offset)));
-}
+ LP_DBG(DEBUG_SETUP, "%s %p\n", __FUNCTION__, (void *) buffer);
+ pipe_buffer_reference(&setup->constants.current, buffer);
-/**
- * Compute a0, dadx and dady for a linearly interpolated coefficient,
- * for a line.
- */
-static void
-line_linear_coeff(struct setup_context *setup,
- unsigned attrib,
- uint vertSlot)
-{
- unsigned i;
- for (i = 0; i < NUM_CHANNELS; ++i) {
- const float da = setup->vmax[vertSlot][i] - setup->vmin[vertSlot][i];
- const float dadx = da * setup->emaj.dx * setup->oneoverarea;
- const float dady = da * setup->emaj.dy * setup->oneoverarea;
- setup->coef.dadx[1 + attrib][i] = dadx;
- setup->coef.dady[1 + attrib][i] = dady;
- setup->coef.a0[1 + attrib][i] = (setup->vmin[vertSlot][i] -
- (dadx * (setup->vmin[0][0] - setup->pixel_offset) +
- dady * (setup->vmin[0][1] - setup->pixel_offset)));
- }
+ setup->dirty |= LP_SETUP_NEW_CONSTANTS;
}
-/**
- * Compute a0, dadx and dady for a perspective-corrected interpolant,
- * for a line.
- */
-static void
-line_persp_coeff(struct setup_context *setup,
- unsigned attrib,
- uint vertSlot)
+void
+lp_setup_set_alpha_ref_value( struct setup_context *setup,
+ float alpha_ref_value )
{
- unsigned i;
- for (i = 0; i < NUM_CHANNELS; ++i) {
- /* XXX double-check/verify this arithmetic */
- const float a0 = setup->vmin[vertSlot][i] * setup->vmin[0][3];
- const float a1 = setup->vmax[vertSlot][i] * setup->vmax[0][3];
- const float da = a1 - a0;
- const float dadx = da * setup->emaj.dx * setup->oneoverarea;
- const float dady = da * setup->emaj.dy * setup->oneoverarea;
- setup->coef.dadx[1 + attrib][i] = dadx;
- setup->coef.dady[1 + attrib][i] = dady;
- setup->coef.a0[1 + attrib][i] = (setup->vmin[vertSlot][i] -
- (dadx * (setup->vmin[0][0] - setup->pixel_offset) +
- dady * (setup->vmin[0][1] - setup->pixel_offset)));
+ LP_DBG(DEBUG_SETUP, "%s %f\n", __FUNCTION__, alpha_ref_value);
+
+ if(setup->fs.current.jit_context.alpha_ref_value != alpha_ref_value) {
+ setup->fs.current.jit_context.alpha_ref_value = alpha_ref_value;
+ setup->dirty |= LP_SETUP_NEW_FS;
}
}
-
-/**
- * Compute the setup->coef[] array dadx, dady, a0 values.
- * Must be called after setup->vmin,vmax are initialized.
- */
-static INLINE boolean
-setup_line_coefficients(struct setup_context *setup,
- const float (*v0)[4],
- const float (*v1)[4])
+void
+lp_setup_set_blend_color( struct setup_context *setup,
+ const struct pipe_blend_color *blend_color )
{
- struct llvmpipe_context *llvmpipe = setup->llvmpipe;
- const struct lp_fragment_shader *lpfs = llvmpipe->fs;
- const struct vertex_info *vinfo = llvmpipe_get_vertex_info(llvmpipe);
- uint fragSlot;
- float area;
-
- /* use setup->vmin, vmax to point to vertices */
- if (llvmpipe->rasterizer->flatshade_first)
- setup->vprovoke = v0;
- else
- setup->vprovoke = v1;
- setup->vmin = v0;
- setup->vmax = v1;
-
- setup->emaj.dx = setup->vmax[0][0] - setup->vmin[0][0];
- setup->emaj.dy = setup->vmax[0][1] - setup->vmin[0][1];
-
- /* NOTE: this is not really area but something proportional to it */
- area = setup->emaj.dx * setup->emaj.dx + setup->emaj.dy * setup->emaj.dy;
- if (area == 0.0f || util_is_inf_or_nan(area))
- return FALSE;
- setup->oneoverarea = 1.0f / area;
-
- /* z and w are done by linear interpolation:
- */
- linear_pos_coeff(setup, 0, 2);
- linear_pos_coeff(setup, 0, 3);
+ LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__);
- /* setup interpolation for all the remaining attributes:
- */
- for (fragSlot = 0; fragSlot < lpfs->info.num_inputs; fragSlot++) {
- const uint vertSlot = vinfo->attrib[fragSlot].src_index;
+ assert(blend_color);
- switch (vinfo->attrib[fragSlot].interp_mode) {
- case INTERP_CONSTANT:
- const_coeff(setup, fragSlot, vertSlot);
- break;
- case INTERP_LINEAR:
- line_linear_coeff(setup, fragSlot, vertSlot);
- break;
- case INTERP_PERSPECTIVE:
- line_persp_coeff(setup, fragSlot, vertSlot);
- break;
- case INTERP_POS:
- setup_fragcoord_coeff(setup, fragSlot);
- break;
- default:
- assert(0);
- }
-
- if (lpfs->info.input_semantic_name[fragSlot] == TGSI_SEMANTIC_FACE) {
- setup->coef.a0[1 + fragSlot][0] = 1.0f - setup->facing;
- setup->coef.dadx[1 + fragSlot][0] = 0.0;
- setup->coef.dady[1 + fragSlot][0] = 0.0;
- }
+ if(memcmp(&setup->blend_color.current, blend_color, sizeof *blend_color) != 0) {
+ memcpy(&setup->blend_color.current, blend_color, sizeof *blend_color);
+ setup->dirty |= LP_SETUP_NEW_BLEND_COLOR;
}
- return TRUE;
}
-/**
- * Plot a pixel in a line segment.
- */
-static INLINE void
-plot(struct setup_context *setup, int x, int y)
+void
+lp_setup_set_flatshade_first( struct setup_context *setup,
+ boolean flatshade_first )
{
- const int iy = y & 1;
- const int ix = x & 1;
- const int quadX = x - ix;
- const int quadY = y - iy;
- const int mask = (1 << ix) << (2 * iy);
-
- if (quadX != setup->quad[0].input.x0 ||
- quadY != setup->quad[0].input.y0)
- {
- /* flush prev quad, start new quad */
-
- if (setup->quad[0].input.x0 != -1)
- clip_emit_quad( setup, &setup->quad[0] );
-
- setup->quad[0].input.x0 = quadX;
- setup->quad[0].input.y0 = quadY;
- setup->quad[0].inout.mask = 0x0;
- }
-
- setup->quad[0].inout.mask |= mask;
+ setup->flatshade_first = flatshade_first;
}
-/**
- * Do setup for line rasterization, then render the line.
- * Single-pixel width, no stipple, etc. We rely on the 'draw' module
- * to handle stippling and wide lines.
- */
-void
-llvmpipe_setup_line(struct setup_context *setup,
- const float (*v0)[4],
- const float (*v1)[4])
+void
+lp_setup_set_vertex_info( struct setup_context *setup,
+ struct vertex_info *vertex_info )
{
- int x0 = (int) v0[0][0];
- int x1 = (int) v1[0][0];
- int y0 = (int) v0[0][1];
- int y1 = (int) v1[0][1];
- int dx = x1 - x0;
- int dy = y1 - y0;
- int xstep, ystep;
-
-#if DEBUG_VERTS
- debug_printf("Setup line:\n");
- print_vertex(setup, v0);
- print_vertex(setup, v1);
-#endif
-
- if (setup->llvmpipe->no_rast)
- return;
+ /* XXX: just silently holding onto the pointer:
+ */
+ setup->vertex_info = vertex_info;
+}
- if (dx == 0 && dy == 0)
- return;
- if (!setup_line_coefficients(setup, v0, v1))
- return;
+void
+lp_setup_set_sampler_textures( struct setup_context *setup,
+ unsigned num, struct pipe_texture **texture)
+{
+ struct pipe_texture *dummy;
+ unsigned i;
- assert(v0[0][0] < 1.0e9);
- assert(v0[0][1] < 1.0e9);
- assert(v1[0][0] < 1.0e9);
- assert(v1[0][1] < 1.0e9);
+ LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__);
- if (dx < 0) {
- dx = -dx; /* make positive */
- xstep = -1;
- }
- else {
- xstep = 1;
- }
- if (dy < 0) {
- dy = -dy; /* make positive */
- ystep = -1;
- }
- else {
- ystep = 1;
- }
+ assert(num <= PIPE_MAX_SAMPLERS);
- assert(dx >= 0);
- assert(dy >= 0);
- assert(setup->llvmpipe->reduced_prim == PIPE_PRIM_LINES);
+ for (i = 0; i < PIPE_MAX_SAMPLERS; i++) {
+ struct pipe_texture *tex = i < num ? texture[i] : NULL;
- setup->quad[0].input.x0 = setup->quad[0].input.y0 = -1;
- setup->quad[0].inout.mask = 0x0;
+ /* FIXME: hold on to the reference */
+ dummy = NULL;
+ pipe_texture_reference(&dummy, tex);
- /* XXX temporary: set coverage to 1.0 so the line appears
- * if AA mode happens to be enabled.
- */
- setup->quad[0].input.coverage[0] =
- setup->quad[0].input.coverage[1] =
- setup->quad[0].input.coverage[2] =
- setup->quad[0].input.coverage[3] = 1.0;
-
- if (dx > dy) {
- /*** X-major line ***/
- int i;
- const int errorInc = dy + dy;
- int error = errorInc - dx;
- const int errorDec = error - dx;
-
- for (i = 0; i < dx; i++) {
- plot(setup, x0, y0);
-
- x0 += xstep;
- if (error < 0) {
- error += errorInc;
- }
- else {
- error += errorDec;
- y0 += ystep;
- }
- }
- }
- else {
- /*** Y-major line ***/
- int i;
- const int errorInc = dx + dx;
- int error = errorInc - dy;
- const int errorDec = error - dy;
-
- for (i = 0; i < dy; i++) {
- plot(setup, x0, y0);
-
- y0 += ystep;
- if (error < 0) {
- error += errorInc;
- }
- else {
- error += errorDec;
- x0 += xstep;
- }
+ if(tex) {
+ struct llvmpipe_texture *lp_tex = llvmpipe_texture(tex);
+ struct lp_jit_texture *jit_tex;
+ jit_tex = &setup->fs.current.jit_context.textures[i];
+ jit_tex->width = tex->width0;
+ jit_tex->height = tex->height0;
+ jit_tex->stride = lp_tex->stride[0];
+ if(!lp_tex->dt)
+ jit_tex->data = lp_tex->data;
+ else
+ /* FIXME: map the rendertarget */
+ assert(0);
}
}
- /* draw final quad */
- if (setup->quad[0].inout.mask) {
- clip_emit_quad( setup, &setup->quad[0] );
- }
+ setup->dirty |= LP_SETUP_NEW_FS;
}
-
-static void
-point_persp_coeff(struct setup_context *setup,
- const float (*vert)[4],
- unsigned attrib,
- uint vertSlot)
+boolean
+lp_setup_is_texture_referenced( struct setup_context *setup,
+ const struct pipe_texture *texture )
{
- unsigned i;
- for(i = 0; i < NUM_CHANNELS; ++i) {
- setup->coef.dadx[1 + attrib][i] = 0.0F;
- setup->coef.dady[1 + attrib][i] = 0.0F;
- setup->coef.a0[1 + attrib][i] = vert[vertSlot][i] * vert[0][3];
- }
+ /* FIXME */
+ return PIPE_UNREFERENCED;
}
-/**
- * Do setup for point rasterization, then render the point.
- * Round or square points...
- * XXX could optimize a lot for 1-pixel points.
- */
void
-llvmpipe_setup_point( struct setup_context *setup,
- const float (*v0)[4] )
+lp_setup_update_state( struct setup_context *setup )
{
- struct llvmpipe_context *llvmpipe = setup->llvmpipe;
- const struct lp_fragment_shader *lpfs = llvmpipe->fs;
- const int sizeAttr = setup->llvmpipe->psize_slot;
- const float size
- = sizeAttr > 0 ? v0[sizeAttr][0]
- : setup->llvmpipe->rasterizer->point_size;
- const float halfSize = 0.5F * size;
- const boolean round = (boolean) setup->llvmpipe->rasterizer->point_smooth;
- const float x = v0[0][0]; /* Note: data[0] is always position */
- const float y = v0[0][1];
- const struct vertex_info *vinfo = llvmpipe_get_vertex_info(llvmpipe);
- uint fragSlot;
-
-#if DEBUG_VERTS
- debug_printf("Setup point:\n");
- print_vertex(setup, v0);
-#endif
-
- if (llvmpipe->no_rast)
- return;
+ struct lp_scene *scene = lp_setup_get_current_scene(setup);
- assert(setup->llvmpipe->reduced_prim == PIPE_PRIM_POINTS);
-
- /* For points, all interpolants are constant-valued.
- * However, for point sprites, we'll need to setup texcoords appropriately.
- * XXX: which coefficients are the texcoords???
- * We may do point sprites as textured quads...
- *
- * KW: We don't know which coefficients are texcoords - ultimately
- * the choice of what interpolation mode to use for each attribute
- * should be determined by the fragment program, using
- * per-attribute declaration statements that include interpolation
- * mode as a parameter. So either the fragment program will have
- * to be adjusted for pointsprite vs normal point behaviour, or
- * otherwise a special interpolation mode will have to be defined
- * which matches the required behaviour for point sprites. But -
- * the latter is not a feature of normal hardware, and as such
- * probably should be ruled out on that basis.
- */
- setup->vprovoke = v0;
+ LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__);
- /* setup Z, W */
- const_pos_coeff(setup, 0, 2);
- const_pos_coeff(setup, 0, 3);
+ assert(setup->fs.current.jit_function);
- for (fragSlot = 0; fragSlot < lpfs->info.num_inputs; fragSlot++) {
- const uint vertSlot = vinfo->attrib[fragSlot].src_index;
+ if(setup->dirty & LP_SETUP_NEW_BLEND_COLOR) {
+ uint8_t *stored;
+ unsigned i, j;
- switch (vinfo->attrib[fragSlot].interp_mode) {
- case INTERP_CONSTANT:
- /* fall-through */
- case INTERP_LINEAR:
- const_coeff(setup, fragSlot, vertSlot);
- break;
- case INTERP_PERSPECTIVE:
- point_persp_coeff(setup, setup->vprovoke, fragSlot, vertSlot);
- break;
- case INTERP_POS:
- setup_fragcoord_coeff(setup, fragSlot);
- break;
- default:
- assert(0);
- }
+ stored = lp_scene_alloc_aligned(scene, 4 * 16, 16);
- if (lpfs->info.input_semantic_name[fragSlot] == TGSI_SEMANTIC_FACE) {
- setup->coef.a0[1 + fragSlot][0] = 1.0f - setup->facing;
- setup->coef.dadx[1 + fragSlot][0] = 0.0;
- setup->coef.dady[1 + fragSlot][0] = 0.0;
+ /* smear each blend color component across 16 ubyte elements */
+ for (i = 0; i < 4; ++i) {
+ uint8_t c = float_to_ubyte(setup->blend_color.current.color[i]);
+ for (j = 0; j < 16; ++j)
+ stored[i*16 + j] = c;
}
- }
+ setup->blend_color.stored = stored;
- if (halfSize <= 0.5 && !round) {
- /* special case for 1-pixel points */
- const int ix = ((int) x) & 1;
- const int iy = ((int) y) & 1;
- setup->quad[0].input.x0 = (int) x - ix;
- setup->quad[0].input.y0 = (int) y - iy;
- setup->quad[0].inout.mask = (1 << ix) << (2 * iy);
- clip_emit_quad( setup, &setup->quad[0] );
+ setup->fs.current.jit_context.blend_color = setup->blend_color.stored;
+ setup->dirty |= LP_SETUP_NEW_FS;
}
- else {
- if (round) {
- /* rounded points */
- const int ixmin = block((int) (x - halfSize));
- const int ixmax = block((int) (x + halfSize));
- const int iymin = block((int) (y - halfSize));
- const int iymax = block((int) (y + halfSize));
- const float rmin = halfSize - 0.7071F; /* 0.7071 = sqrt(2)/2 */
- const float rmax = halfSize + 0.7071F;
- const float rmin2 = MAX2(0.0F, rmin * rmin);
- const float rmax2 = rmax * rmax;
- const float cscale = 1.0F / (rmax2 - rmin2);
- int ix, iy;
-
- for (iy = iymin; iy <= iymax; iy += 2) {
- for (ix = ixmin; ix <= ixmax; ix += 2) {
- float dx, dy, dist2, cover;
-
- setup->quad[0].inout.mask = 0x0;
-
- dx = (ix + 0.5f) - x;
- dy = (iy + 0.5f) - y;
- dist2 = dx * dx + dy * dy;
- if (dist2 <= rmax2) {
- cover = 1.0F - (dist2 - rmin2) * cscale;
- setup->quad[0].input.coverage[QUAD_TOP_LEFT] = MIN2(cover, 1.0f);
- setup->quad[0].inout.mask |= MASK_TOP_LEFT;
- }
-
- dx = (ix + 1.5f) - x;
- dy = (iy + 0.5f) - y;
- dist2 = dx * dx + dy * dy;
- if (dist2 <= rmax2) {
- cover = 1.0F - (dist2 - rmin2) * cscale;
- setup->quad[0].input.coverage[QUAD_TOP_RIGHT] = MIN2(cover, 1.0f);
- setup->quad[0].inout.mask |= MASK_TOP_RIGHT;
- }
-
- dx = (ix + 0.5f) - x;
- dy = (iy + 1.5f) - y;
- dist2 = dx * dx + dy * dy;
- if (dist2 <= rmax2) {
- cover = 1.0F - (dist2 - rmin2) * cscale;
- setup->quad[0].input.coverage[QUAD_BOTTOM_LEFT] = MIN2(cover, 1.0f);
- setup->quad[0].inout.mask |= MASK_BOTTOM_LEFT;
- }
-
- dx = (ix + 1.5f) - x;
- dy = (iy + 1.5f) - y;
- dist2 = dx * dx + dy * dy;
- if (dist2 <= rmax2) {
- cover = 1.0F - (dist2 - rmin2) * cscale;
- setup->quad[0].input.coverage[QUAD_BOTTOM_RIGHT] = MIN2(cover, 1.0f);
- setup->quad[0].inout.mask |= MASK_BOTTOM_RIGHT;
- }
-
- if (setup->quad[0].inout.mask) {
- setup->quad[0].input.x0 = ix;
- setup->quad[0].input.y0 = iy;
- clip_emit_quad( setup, &setup->quad[0] );
- }
+
+
+ if(setup->dirty & LP_SETUP_NEW_CONSTANTS) {
+ struct pipe_buffer *buffer = setup->constants.current;
+
+ if(buffer) {
+ unsigned current_size = buffer->size;
+ const void *current_data = llvmpipe_buffer(buffer)->data;
+
+ /* TODO: copy only the actually used constants? */
+
+ if(setup->constants.stored_size != current_size ||
+ !setup->constants.stored_data ||
+ memcmp(setup->constants.stored_data,
+ current_data,
+ current_size) != 0) {
+ void *stored;
+
+ stored = lp_scene_alloc(scene, current_size);
+ if(stored) {
+ memcpy(stored,
+ current_data,
+ current_size);
+ setup->constants.stored_size = current_size;
+ setup->constants.stored_data = stored;
}
}
}
else {
- /* square points */
- const int xmin = (int) (x + 0.75 - halfSize);
- const int ymin = (int) (y + 0.25 - halfSize);
- const int xmax = xmin + (int) size;
- const int ymax = ymin + (int) size;
- /* XXX could apply scissor to xmin,ymin,xmax,ymax now */
- const int ixmin = block(xmin);
- const int ixmax = block(xmax - 1);
- const int iymin = block(ymin);
- const int iymax = block(ymax - 1);
- int ix, iy;
-
- /*
- debug_printf("(%f, %f) -> X:%d..%d Y:%d..%d\n", x, y, xmin, xmax,ymin,ymax);
- */
- for (iy = iymin; iy <= iymax; iy += 2) {
- uint rowMask = 0xf;
- if (iy < ymin) {
- /* above the top edge */
- rowMask &= (MASK_BOTTOM_LEFT | MASK_BOTTOM_RIGHT);
- }
- if (iy + 1 >= ymax) {
- /* below the bottom edge */
- rowMask &= (MASK_TOP_LEFT | MASK_TOP_RIGHT);
- }
+ setup->constants.stored_size = 0;
+ setup->constants.stored_data = NULL;
+ }
- for (ix = ixmin; ix <= ixmax; ix += 2) {
- uint mask = rowMask;
-
- if (ix < xmin) {
- /* fragment is past left edge of point, turn off left bits */
- mask &= (MASK_BOTTOM_RIGHT | MASK_TOP_RIGHT);
- }
- if (ix + 1 >= xmax) {
- /* past the right edge */
- mask &= (MASK_BOTTOM_LEFT | MASK_TOP_LEFT);
- }
-
- setup->quad[0].inout.mask = mask;
- setup->quad[0].input.x0 = ix;
- setup->quad[0].input.y0 = iy;
- clip_emit_quad( setup, &setup->quad[0] );
- }
+ setup->fs.current.jit_context.constants = setup->constants.stored_data;
+ setup->dirty |= LP_SETUP_NEW_FS;
+ }
+
+
+ if(setup->dirty & LP_SETUP_NEW_FS) {
+ if(!setup->fs.stored ||
+ memcmp(setup->fs.stored,
+ &setup->fs.current,
+ sizeof setup->fs.current) != 0) {
+ /* The fs state that's been stored in the scene is different from
+ * the new, current state. So allocate a new lp_rast_state object
+ * and append it to the bin's setup data buffer.
+ */
+ struct lp_rast_state *stored =
+ (struct lp_rast_state *) lp_scene_alloc(scene, sizeof *stored);
+ if(stored) {
+ memcpy(stored,
+ &setup->fs.current,
+ sizeof setup->fs.current);
+ setup->fs.stored = stored;
+
+ /* put the state-set command into all bins */
+ lp_scene_bin_state_command( scene,
+ lp_rast_set_state,
+ lp_rast_arg_state(setup->fs.stored) );
}
}
}
+
+ setup->dirty = 0;
+
+ assert(setup->fs.stored);
}
-void llvmpipe_setup_prepare( struct setup_context *setup )
+
+
+/* Only caller is lp_setup_vbuf_destroy()
+ */
+void
+lp_setup_destroy( struct setup_context *setup )
{
- struct llvmpipe_context *lp = setup->llvmpipe;
+ reset_context( setup );
- if (lp->dirty) {
- llvmpipe_update_derived(lp);
- }
+ pipe_buffer_reference(&setup->constants.current, NULL);
- if (lp->reduced_api_prim == PIPE_PRIM_TRIANGLES &&
- lp->rasterizer->fill_cw == PIPE_POLYGON_MODE_FILL &&
- lp->rasterizer->fill_ccw == PIPE_POLYGON_MODE_FILL) {
- /* we'll do culling */
- setup->winding = lp->rasterizer->cull_mode;
- }
- else {
- /* 'draw' will do culling */
- setup->winding = PIPE_WINDING_NONE;
+ /* free the scenes in the 'empty' queue */
+ while (lp_scene_queue_count(setup->empty_scenes) > 0) {
+ struct lp_scene *scene = lp_scene_dequeue(setup->empty_scenes);
+ if (!scene)
+ break;
+ lp_scene_destroy(scene);
}
-}
-
+ lp_rast_destroy( setup->rast );
-void llvmpipe_setup_destroy_context( struct setup_context *setup )
-{
- align_free( setup );
+ FREE( setup );
}
/**
- * Create a new primitive setup/render stage.
+ * Create a new primitive tiling engine. Plug it into the backend of
+ * the draw module. Currently also creates a rasterizer to use with
+ * it.
*/
-struct setup_context *llvmpipe_setup_create_context( struct llvmpipe_context *llvmpipe )
+struct setup_context *
+lp_setup_create( struct pipe_screen *screen,
+ struct draw_context *draw )
{
- struct setup_context *setup;
unsigned i;
+ struct setup_context *setup = CALLOC_STRUCT(setup_context);
- setup = align_malloc(sizeof(struct setup_context), 16);
if (!setup)
return NULL;
- memset(setup, 0, sizeof *setup);
- setup->llvmpipe = llvmpipe;
+ lp_setup_init_vbuf(setup);
+
+ setup->empty_scenes = lp_scene_queue_create();
+ if (!setup->empty_scenes)
+ goto fail;
- for (i = 0; i < MAX_QUADS; i++) {
- setup->quad[i].coef = &setup->coef;
+ setup->rast = lp_rast_create( screen, setup->empty_scenes );
+ if (!setup->rast)
+ goto fail;
+
+ setup->vbuf = draw_vbuf_stage(draw, &setup->base);
+ if (!setup->vbuf)
+ goto fail;
+
+ draw_set_rasterize_stage(draw, setup->vbuf);
+ draw_set_render(draw, &setup->base);
+
+ /* create some empty scenes */
+ for (i = 0; i < MAX_SCENES; i++) {
+ struct lp_scene *scene = lp_scene_create();
+ lp_scene_enqueue(setup->empty_scenes, scene);
}
- setup->span.left[0] = 1000000; /* greater than right[0] */
- setup->span.left[1] = 1000000; /* greater than right[1] */
+ setup->triangle = first_triangle;
+ setup->line = first_line;
+ setup->point = first_point;
+
+ setup->dirty = ~0;
return setup;
+
+fail:
+ if (setup->rast)
+ lp_rast_destroy( setup->rast );
+
+ if (setup->vbuf)
+ ;
+
+ if (setup->empty_scenes)
+ lp_scene_queue_destroy(setup->empty_scenes);
+
+ FREE(setup);
+ return NULL;
}
diff --git a/src/gallium/drivers/llvmpipe/lp_setup.h b/src/gallium/drivers/llvmpipe/lp_setup.h
index 89c43da046..bf12cb8527 100644
--- a/src/gallium/drivers/llvmpipe/lp_setup.h
+++ b/src/gallium/drivers/llvmpipe/lp_setup.h
@@ -27,27 +27,106 @@
#ifndef LP_SETUP_H
#define LP_SETUP_H
-struct setup_context;
-struct llvmpipe_context;
+#include "pipe/p_compiler.h"
+#include "lp_jit.h"
+
+struct draw_context;
+struct vertex_info;
+
+enum lp_interp {
+ LP_INTERP_CONSTANT,
+ LP_INTERP_LINEAR,
+ LP_INTERP_PERSPECTIVE,
+ LP_INTERP_POSITION,
+ LP_INTERP_FACING
+};
+
+/* Describes how to generate all the fragment shader inputs from the
+ * the vertices passed into our triangle/line/point functions.
+ *
+ * Vertices are treated as an array of float[4] values, indexed by
+ * src_index.
+ */
+struct lp_shader_input {
+ enum lp_interp interp; /* how to interpolate values */
+ unsigned src_index; /* where to find values in incoming vertices */
+};
+
+struct pipe_texture;
+struct pipe_surface;
+struct pipe_buffer;
+struct pipe_blend_color;
+struct pipe_screen;
+struct pipe_framebuffer_state;
+struct lp_fragment_shader;
+struct lp_jit_context;
+
+struct setup_context *
+lp_setup_create( struct pipe_screen *screen,
+ struct draw_context *draw );
+
+void
+lp_setup_clear(struct setup_context *setup,
+ const float *clear_color,
+ double clear_depth,
+ unsigned clear_stencil,
+ unsigned flags);
+
+struct pipe_fence_handle *
+lp_setup_fence( struct setup_context *setup );
+
+
+void
+lp_setup_flush( struct setup_context *setup,
+ unsigned flags );
+
+
+void
+lp_setup_bind_framebuffer( struct setup_context *setup,
+ const struct pipe_framebuffer_state *fb );
void
-llvmpipe_setup_tri( struct setup_context *setup,
- const float (*v0)[4],
- const float (*v1)[4],
- const float (*v2)[4] );
+lp_setup_set_triangle_state( struct setup_context *setup,
+ unsigned cullmode,
+ boolean front_is_ccw );
+
+void
+lp_setup_set_fs_inputs( struct setup_context *setup,
+ const struct lp_shader_input *interp,
+ unsigned nr );
+
+void
+lp_setup_set_fs_function( struct setup_context *setup,
+ lp_jit_frag_func jit_function );
+
+void
+lp_setup_set_fs_constants(struct setup_context *setup,
+ struct pipe_buffer *buffer);
+
+
+void
+lp_setup_set_alpha_ref_value( struct setup_context *setup,
+ float alpha_ref_value );
void
-llvmpipe_setup_line(struct setup_context *setup,
- const float (*v0)[4],
- const float (*v1)[4]);
+lp_setup_set_blend_color( struct setup_context *setup,
+ const struct pipe_blend_color *blend_color );
void
-llvmpipe_setup_point( struct setup_context *setup,
- const float (*v0)[4] );
+lp_setup_set_sampler_textures( struct setup_context *setup,
+ unsigned num, struct pipe_texture **texture);
+
+boolean
+lp_setup_is_texture_referenced( struct setup_context *setup,
+ const struct pipe_texture *texture );
+void
+lp_setup_set_flatshade_first( struct setup_context *setup,
+ boolean flatshade_first );
+
+void
+lp_setup_set_vertex_info( struct setup_context *setup,
+ struct vertex_info *info );
-struct setup_context *llvmpipe_setup_create_context( struct llvmpipe_context *llvmpipe );
-void llvmpipe_setup_prepare( struct setup_context *setup );
-void llvmpipe_setup_destroy_context( struct setup_context *setup );
#endif
diff --git a/src/gallium/drivers/llvmpipe/lp_setup_context.h b/src/gallium/drivers/llvmpipe/lp_setup_context.h
new file mode 100644
index 0000000000..a1808fcd4c
--- /dev/null
+++ b/src/gallium/drivers/llvmpipe/lp_setup_context.h
@@ -0,0 +1,146 @@
+/**************************************************************************
+ *
+ * Copyright 2007-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.
+ *
+ **************************************************************************/
+
+
+/**
+ * The setup code is concerned with point/line/triangle setup and
+ * putting commands/data into the bins.
+ */
+
+
+#ifndef LP_SETUP_CONTEXT_H
+#define LP_SETUP_CONTEXT_H
+
+#include "lp_setup.h"
+#include "lp_rast.h"
+#include "lp_tile_soa.h" /* for TILE_SIZE */
+#include "lp_scene.h"
+
+#include "draw/draw_vbuf.h"
+
+#define LP_SETUP_NEW_FS 0x01
+#define LP_SETUP_NEW_CONSTANTS 0x02
+#define LP_SETUP_NEW_BLEND_COLOR 0x04
+
+
+struct lp_scene_queue;
+
+
+/**
+ * Point/line/triangle setup context.
+ * Note: "stored" below indicates data which is stored in the bins,
+ * not arbitrary malloc'd memory.
+ *
+ *
+ * Subclass of vbuf_render, plugged directly into the draw module as
+ * the rendering backend.
+ */
+struct setup_context
+{
+ struct vbuf_render base;
+
+ struct vertex_info *vertex_info;
+ uint prim;
+ uint vertex_size;
+ uint nr_vertices;
+ uint vertex_buffer_size;
+ void *vertex_buffer;
+
+ /* Final pipeline stage for draw module. Draw module should
+ * create/install this itself now.
+ */
+ struct draw_stage *vbuf;
+ struct lp_rasterizer *rast;
+ struct lp_scene *scene; /**< current scene */
+ struct lp_scene_queue *empty_scenes; /**< queue of empty scenes */
+
+ boolean flatshade_first;
+ boolean ccw_is_frontface;
+ unsigned cullmode;
+
+ struct pipe_framebuffer_state fb;
+
+ struct {
+ unsigned flags;
+ union lp_rast_cmd_arg color; /**< lp_rast_clear_color() cmd */
+ union lp_rast_cmd_arg zstencil; /**< lp_rast_clear_zstencil() cmd */
+ } clear;
+
+ enum {
+ SETUP_FLUSHED,
+ SETUP_CLEARED,
+ SETUP_ACTIVE
+ } state;
+
+ struct {
+ struct lp_shader_input input[PIPE_MAX_ATTRIBS];
+ unsigned nr_inputs;
+
+ const struct lp_rast_state *stored; /**< what's in the scene */
+ struct lp_rast_state current; /**< currently set state */
+ } fs;
+
+ /** fragment shader constants */
+ struct {
+ struct pipe_buffer *current;
+ unsigned stored_size;
+ const void *stored_data;
+ } constants;
+
+ struct {
+ struct pipe_blend_color current;
+ uint8_t *stored;
+ } blend_color;
+
+ unsigned dirty; /**< bitmask of LP_SETUP_x bits */
+
+ void (*point)( struct setup_context *,
+ const float (*v0)[4]);
+
+ void (*line)( struct setup_context *,
+ const float (*v0)[4],
+ const float (*v1)[4]);
+
+ void (*triangle)( struct setup_context *,
+ const float (*v0)[4],
+ const float (*v1)[4],
+ const float (*v2)[4]);
+};
+
+void lp_setup_choose_triangle( struct setup_context *setup );
+void lp_setup_choose_line( struct setup_context *setup );
+void lp_setup_choose_point( struct setup_context *setup );
+
+struct lp_scene *lp_setup_get_current_scene(struct setup_context *setup);
+
+void lp_setup_init_vbuf(struct setup_context *setup);
+
+void lp_setup_update_state( struct setup_context *setup );
+
+void lp_setup_destroy( struct setup_context *setup );
+
+#endif
diff --git a/src/gallium/drivers/llvmpipe/lp_tile_cache.h b/src/gallium/drivers/llvmpipe/lp_setup_line.c
index 161bab3799..feea79d394 100644
--- a/src/gallium/drivers/llvmpipe/lp_tile_cache.h
+++ b/src/gallium/drivers/llvmpipe/lp_setup_line.c
@@ -1,8 +1,8 @@
/**************************************************************************
- *
+ *
* Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
* 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
@@ -10,11 +10,11 @@
* 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.
@@ -22,50 +22,26 @@
* 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 LP_TILE_CACHE_H
-#define LP_TILE_CACHE_H
+/*
+ * Binning code for lines
+ */
+#include "lp_setup_context.h"
-#include "pipe/p_compiler.h"
-#include "lp_tile_soa.h"
+static void line_nop( struct setup_context *setup,
+ const float (*v0)[4],
+ const float (*v1)[4] )
+{
+}
-struct llvmpipe_tile_cache; /* opaque */
+void
+lp_setup_choose_line( struct setup_context *setup )
+{
+ setup->line = line_nop;
+}
-extern struct llvmpipe_tile_cache *
-lp_create_tile_cache( struct pipe_screen *screen );
-
-extern void
-lp_destroy_tile_cache(struct llvmpipe_tile_cache *tc);
-
-extern void
-lp_tile_cache_set_surface(struct llvmpipe_tile_cache *tc,
- struct pipe_surface *lps);
-
-extern struct pipe_surface *
-lp_tile_cache_get_surface(struct llvmpipe_tile_cache *tc);
-
-extern void
-lp_tile_cache_map_transfers(struct llvmpipe_tile_cache *tc);
-
-extern void
-lp_tile_cache_unmap_transfers(struct llvmpipe_tile_cache *tc);
-
-extern void
-lp_flush_tile_cache(struct llvmpipe_tile_cache *tc);
-
-extern void
-lp_tile_cache_clear(struct llvmpipe_tile_cache *tc, const float *rgba,
- uint clearValue);
-
-extern void *
-lp_get_cached_tile(struct llvmpipe_tile_cache *tc,
- unsigned x, unsigned y );
-
-
-#endif /* LP_TILE_CACHE_H */
-
diff --git a/src/gallium/drivers/llvmpipe/lp_prim_vbuf.h b/src/gallium/drivers/llvmpipe/lp_setup_point.c
index 0676e2f42a..f03ca729b2 100644
--- a/src/gallium/drivers/llvmpipe/lp_prim_vbuf.h
+++ b/src/gallium/drivers/llvmpipe/lp_setup_point.c
@@ -1,8 +1,8 @@
/**************************************************************************
- *
+ *
* Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
* 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
@@ -10,11 +10,11 @@
* 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.
@@ -22,17 +22,25 @@
* 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 LP_VBUF_H
-#define LP_VBUF_H
+/*
+ * Binning code for points
+ */
+#include "lp_setup_context.h"
-struct llvmpipe_context;
+static void point_nop( struct setup_context *setup,
+ const float (*v0)[4] )
+{
+}
-extern struct vbuf_render *
-lp_create_vbuf_backend(struct llvmpipe_context *llvmpipe);
+
+void
+lp_setup_choose_point( struct setup_context *setup )
+{
+ setup->point = point_nop;
+}
-#endif /* LP_VBUF_H */
diff --git a/src/gallium/drivers/llvmpipe/lp_setup_tri.c b/src/gallium/drivers/llvmpipe/lp_setup_tri.c
new file mode 100644
index 0000000000..fe34903cf3
--- /dev/null
+++ b/src/gallium/drivers/llvmpipe/lp_setup_tri.c
@@ -0,0 +1,547 @@
+/**************************************************************************
+ *
+ * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * 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 TUNGSTEN GRAPHICS 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.
+ *
+ **************************************************************************/
+
+/*
+ * Binning code for triangles
+ */
+
+#include "lp_setup_context.h"
+#include "lp_rast.h"
+#include "util/u_math.h"
+#include "util/u_memory.h"
+
+#define NUM_CHANNELS 4
+
+/**
+ * Compute a0 for a constant-valued coefficient (GL_FLAT shading).
+ */
+static void constant_coef( struct lp_rast_triangle *tri,
+ unsigned slot,
+ const float value,
+ unsigned i )
+{
+ tri->inputs.a0[slot][i] = value;
+ tri->inputs.dadx[slot][i] = 0;
+ tri->inputs.dady[slot][i] = 0;
+}
+
+/**
+ * Compute a0, dadx and dady for a linearly interpolated coefficient,
+ * for a triangle.
+ */
+static void linear_coef( struct lp_rast_triangle *tri,
+ float oneoverarea,
+ unsigned slot,
+ const float (*v1)[4],
+ const float (*v2)[4],
+ const float (*v3)[4],
+ unsigned vert_attr,
+ unsigned i)
+{
+ float a1 = v1[vert_attr][i];
+ float a2 = v2[vert_attr][i];
+ float a3 = v3[vert_attr][i];
+
+ float da12 = a1 - a2;
+ float da31 = a3 - a1;
+ float dadx = (da12 * tri->dy31 - tri->dy12 * da31) * oneoverarea;
+ float dady = (da31 * tri->dx12 - tri->dx31 * da12) * oneoverarea;
+
+ tri->inputs.dadx[slot][i] = dadx;
+ tri->inputs.dady[slot][i] = dady;
+
+ /* calculate a0 as the value which would be sampled for the
+ * fragment at (0,0), taking into account that we want to sample at
+ * pixel centers, in other words (0.5, 0.5).
+ *
+ * this is neat but unfortunately not a good way to do things for
+ * triangles with very large values of dadx or dady as it will
+ * result in the subtraction and re-addition from a0 of a very
+ * large number, which means we'll end up loosing a lot of the
+ * fractional bits and precision from a0. the way to fix this is
+ * to define a0 as the sample at a pixel center somewhere near vmin
+ * instead - i'll switch to this later.
+ */
+ tri->inputs.a0[slot][i] = (v1[vert_attr][i] -
+ (dadx * (v1[0][0] - 0.5f) +
+ dady * (v1[0][1] - 0.5f)));
+}
+
+
+/**
+ * Compute a0, dadx and dady for a perspective-corrected interpolant,
+ * for a triangle.
+ * We basically multiply the vertex value by 1/w before computing
+ * the plane coefficients (a0, dadx, dady).
+ * Later, when we compute the value at a particular fragment position we'll
+ * divide the interpolated value by the interpolated W at that fragment.
+ */
+static void perspective_coef( struct lp_rast_triangle *tri,
+ float oneoverarea,
+ unsigned slot,
+ const float (*v1)[4],
+ const float (*v2)[4],
+ const float (*v3)[4],
+ unsigned vert_attr,
+ unsigned i)
+{
+ /* premultiply by 1/w (v[0][3] is always 1/w):
+ */
+ float a1 = v1[vert_attr][i] * v1[0][3];
+ float a2 = v2[vert_attr][i] * v2[0][3];
+ float a3 = v3[vert_attr][i] * v3[0][3];
+ float da12 = a1 - a2;
+ float da31 = a3 - a1;
+ float dadx = (da12 * tri->dy31 - tri->dy12 * da31) * oneoverarea;
+ float dady = (da31 * tri->dx12 - tri->dx31 * da12) * oneoverarea;
+
+ tri->inputs.dadx[slot][i] = dadx;
+ tri->inputs.dady[slot][i] = dady;
+ tri->inputs.a0[slot][i] = (a1 -
+ (dadx * (v1[0][0] - 0.5f) +
+ dady * (v1[0][1] - 0.5f)));
+}
+
+
+/**
+ * Special coefficient setup for gl_FragCoord.
+ * X and Y are trivial, though Y has to be inverted for OpenGL.
+ * Z and W are copied from position_coef which should have already been computed.
+ * We could do a bit less work if we'd examine gl_FragCoord's swizzle mask.
+ */
+static void
+setup_fragcoord_coef(struct lp_rast_triangle *tri,
+ float oneoverarea,
+ unsigned slot,
+ const float (*v1)[4],
+ const float (*v2)[4],
+ const float (*v3)[4])
+{
+ /*X*/
+ tri->inputs.a0[slot][0] = 0.0;
+ tri->inputs.dadx[slot][0] = 1.0;
+ tri->inputs.dady[slot][0] = 0.0;
+ /*Y*/
+ tri->inputs.a0[slot][1] = 0.0;
+ tri->inputs.dadx[slot][1] = 0.0;
+ tri->inputs.dady[slot][1] = 1.0;
+ /*Z*/
+ linear_coef(tri, oneoverarea, slot, v1, v2, v3, 0, 2);
+ /*W*/
+ linear_coef(tri, oneoverarea, slot, v1, v2, v3, 0, 3);
+}
+
+
+static void setup_facing_coef( struct lp_rast_triangle *tri,
+ unsigned slot,
+ boolean frontface )
+{
+ constant_coef( tri, slot, 1.0f - frontface, 0 );
+ constant_coef( tri, slot, 0.0f, 1 ); /* wasted */
+ constant_coef( tri, slot, 0.0f, 2 ); /* wasted */
+ constant_coef( tri, slot, 0.0f, 3 ); /* wasted */
+}
+
+
+/**
+ * Compute the tri->coef[] array dadx, dady, a0 values.
+ */
+static void setup_tri_coefficients( struct setup_context *setup,
+ struct lp_rast_triangle *tri,
+ float oneoverarea,
+ const float (*v1)[4],
+ const float (*v2)[4],
+ const float (*v3)[4],
+ boolean frontface)
+{
+ struct lp_scene *scene = lp_setup_get_current_scene(setup);
+ unsigned slot;
+
+ /* Allocate space for the a0, dadx and dady arrays
+ */
+ {
+ unsigned bytes;
+ bytes = (setup->fs.nr_inputs + 1) * 4 * sizeof(float);
+ tri->inputs.a0 = lp_scene_alloc_aligned( scene, bytes, 16 );
+ tri->inputs.dadx = lp_scene_alloc_aligned( scene, bytes, 16 );
+ tri->inputs.dady = lp_scene_alloc_aligned( scene, bytes, 16 );
+ }
+
+ /* The internal position input is in slot zero:
+ */
+ setup_fragcoord_coef(tri, oneoverarea, 0, v1, v2, v3);
+
+ /* setup interpolation for all the remaining attributes:
+ */
+ for (slot = 0; slot < setup->fs.nr_inputs; slot++) {
+ unsigned vert_attr = setup->fs.input[slot].src_index;
+ unsigned i;
+
+ switch (setup->fs.input[slot].interp) {
+ case LP_INTERP_CONSTANT:
+ for (i = 0; i < NUM_CHANNELS; i++)
+ constant_coef(tri, slot+1, v3[vert_attr][i], i);
+ break;
+
+ case LP_INTERP_LINEAR:
+ for (i = 0; i < NUM_CHANNELS; i++)
+ linear_coef(tri, oneoverarea, slot+1, v1, v2, v3, vert_attr, i);
+ break;
+
+ case LP_INTERP_PERSPECTIVE:
+ for (i = 0; i < NUM_CHANNELS; i++)
+ perspective_coef(tri, oneoverarea, slot+1, v1, v2, v3, vert_attr, i);
+ break;
+
+ case LP_INTERP_POSITION:
+ /* XXX: fix me - duplicates the values in slot zero.
+ */
+ setup_fragcoord_coef(tri, oneoverarea, slot+1, v1, v2, v3);
+ break;
+
+ case LP_INTERP_FACING:
+ setup_facing_coef(tri, slot+1, frontface);
+ break;
+
+ default:
+ assert(0);
+ }
+ }
+}
+
+
+
+static inline int subpixel_snap( float a )
+{
+ return util_iround(FIXED_ONE * a);
+}
+
+
+/**
+ * Do basic setup for triangle rasterization and determine which
+ * framebuffer tiles are touched. Put the triangle in the scene's
+ * bins for the tiles which we overlap.
+ */
+static void
+do_triangle_ccw(struct setup_context *setup,
+ const float (*v1)[4],
+ const float (*v2)[4],
+ const float (*v3)[4],
+ boolean frontfacing )
+{
+ /* x/y positions in fixed point */
+ const int x1 = subpixel_snap(v1[0][0]);
+ const int x2 = subpixel_snap(v2[0][0]);
+ const int x3 = subpixel_snap(v3[0][0]);
+ const int y1 = subpixel_snap(v1[0][1]);
+ const int y2 = subpixel_snap(v2[0][1]);
+ const int y3 = subpixel_snap(v3[0][1]);
+
+ struct lp_scene *scene = lp_setup_get_current_scene(setup);
+ struct lp_rast_triangle *tri = lp_scene_alloc_aligned( scene, sizeof *tri, 16 );
+ float area, oneoverarea;
+ int minx, maxx, miny, maxy;
+
+ tri->dx12 = x1 - x2;
+ tri->dx23 = x2 - x3;
+ tri->dx31 = x3 - x1;
+
+ tri->dy12 = y1 - y2;
+ tri->dy23 = y2 - y3;
+ tri->dy31 = y3 - y1;
+
+ area = (tri->dx12 * tri->dy31 -
+ tri->dx31 * tri->dy12);
+
+ /* Cull non-ccw and zero-sized triangles.
+ *
+ * XXX: subject to overflow??
+ */
+ if (area <= 0) {
+ lp_scene_putback_data( scene, sizeof *tri );
+ return;
+ }
+
+ /* Bounding rectangle (in pixels) */
+ tri->minx = (MIN3(x1, x2, x3) + 0xf) >> FIXED_ORDER;
+ tri->maxx = (MAX3(x1, x2, x3) + 0xf) >> FIXED_ORDER;
+ tri->miny = (MIN3(y1, y2, y3) + 0xf) >> FIXED_ORDER;
+ tri->maxy = (MAX3(y1, y2, y3) + 0xf) >> FIXED_ORDER;
+
+ if (tri->miny == tri->maxy ||
+ tri->minx == tri->maxx) {
+ lp_scene_putback_data( scene, sizeof *tri );
+ return;
+ }
+
+ /*
+ */
+ oneoverarea = ((float)FIXED_ONE) / (float)area;
+
+ /* Setup parameter interpolants:
+ */
+ setup_tri_coefficients( setup, tri, oneoverarea, v1, v2, v3, frontfacing );
+
+ /* half-edge constants, will be interated over the whole
+ * rendertarget.
+ */
+ tri->c1 = tri->dy12 * x1 - tri->dx12 * y1;
+ tri->c2 = tri->dy23 * x2 - tri->dx23 * y2;
+ tri->c3 = tri->dy31 * x3 - tri->dx31 * y3;
+
+ /* correct for top-left fill convention:
+ */
+ if (tri->dy12 < 0 || (tri->dy12 == 0 && tri->dx12 > 0)) tri->c1++;
+ if (tri->dy23 < 0 || (tri->dy23 == 0 && tri->dx23 > 0)) tri->c2++;
+ if (tri->dy31 < 0 || (tri->dy31 == 0 && tri->dx31 > 0)) tri->c3++;
+
+ tri->dy12 *= FIXED_ONE;
+ tri->dy23 *= FIXED_ONE;
+ tri->dy31 *= FIXED_ONE;
+
+ tri->dx12 *= FIXED_ONE;
+ tri->dx23 *= FIXED_ONE;
+ tri->dx31 *= FIXED_ONE;
+
+ /* find trivial reject offsets for each edge for a single-pixel
+ * sized block. These will be scaled up at each recursive level to
+ * match the active blocksize. Scaling in this way works best if
+ * the blocks are square.
+ */
+ tri->eo1 = 0;
+ if (tri->dy12 < 0) tri->eo1 -= tri->dy12;
+ if (tri->dx12 > 0) tri->eo1 += tri->dx12;
+
+ tri->eo2 = 0;
+ if (tri->dy23 < 0) tri->eo2 -= tri->dy23;
+ if (tri->dx23 > 0) tri->eo2 += tri->dx23;
+
+ tri->eo3 = 0;
+ if (tri->dy31 < 0) tri->eo3 -= tri->dy31;
+ if (tri->dx31 > 0) tri->eo3 += tri->dx31;
+
+ /* Calculate trivial accept offsets from the above.
+ */
+ tri->ei1 = tri->dx12 - tri->dy12 - tri->eo1;
+ tri->ei2 = tri->dx23 - tri->dy23 - tri->eo2;
+ tri->ei3 = tri->dx31 - tri->dy31 - tri->eo3;
+
+ {
+ const int xstep1 = -tri->dy12;
+ const int xstep2 = -tri->dy23;
+ const int xstep3 = -tri->dy31;
+
+ const int ystep1 = tri->dx12;
+ const int ystep2 = tri->dx23;
+ const int ystep3 = tri->dx31;
+
+ int qx, qy, ix, iy;
+ int i = 0;
+
+ for (qy = 0; qy < 2; qy++) {
+ for (qx = 0; qx < 2; qx++) {
+ for (iy = 0; iy < 2; iy++) {
+ for (ix = 0; ix < 2; ix++, i++) {
+ int x = qx * 2 + ix;
+ int y = qy * 2 + iy;
+ tri->inputs.step[0][i] = x * xstep1 + y * ystep1;
+ tri->inputs.step[1][i] = x * xstep2 + y * ystep2;
+ tri->inputs.step[2][i] = x * xstep3 + y * ystep3;
+ }
+ }
+ }
+ }
+ }
+
+ /*
+ * All fields of 'tri' are now set. The remaining code here is
+ * concerned with binning.
+ */
+
+ /* Convert to tile coordinates:
+ */
+ minx = tri->minx / TILE_SIZE;
+ miny = tri->miny / TILE_SIZE;
+ maxx = tri->maxx / TILE_SIZE;
+ maxy = tri->maxy / TILE_SIZE;
+
+ /* Determine which tile(s) intersect the triangle's bounding box
+ */
+ if (miny == maxy && minx == maxx)
+ {
+ /* Triangle is contained in a single tile:
+ */
+ lp_scene_bin_command( scene, minx, miny, lp_rast_triangle,
+ lp_rast_arg_triangle(tri) );
+ }
+ else
+ {
+ int c1 = (tri->c1 +
+ tri->dx12 * miny * TILE_SIZE -
+ tri->dy12 * minx * TILE_SIZE);
+ int c2 = (tri->c2 +
+ tri->dx23 * miny * TILE_SIZE -
+ tri->dy23 * minx * TILE_SIZE);
+ int c3 = (tri->c3 +
+ tri->dx31 * miny * TILE_SIZE -
+ tri->dy31 * minx * TILE_SIZE);
+
+ int ei1 = tri->ei1 << TILE_ORDER;
+ int ei2 = tri->ei2 << TILE_ORDER;
+ int ei3 = tri->ei3 << TILE_ORDER;
+
+ int eo1 = tri->eo1 << TILE_ORDER;
+ int eo2 = tri->eo2 << TILE_ORDER;
+ int eo3 = tri->eo3 << TILE_ORDER;
+
+ int xstep1 = -(tri->dy12 << TILE_ORDER);
+ int xstep2 = -(tri->dy23 << TILE_ORDER);
+ int xstep3 = -(tri->dy31 << TILE_ORDER);
+
+ int ystep1 = tri->dx12 << TILE_ORDER;
+ int ystep2 = tri->dx23 << TILE_ORDER;
+ int ystep3 = tri->dx31 << TILE_ORDER;
+ int x, y;
+
+
+ /* Trivially accept or reject blocks, else jump to per-pixel
+ * examination above.
+ */
+ for (y = miny; y <= maxy; y++)
+ {
+ int cx1 = c1;
+ int cx2 = c2;
+ int cx3 = c3;
+ int in = 0;
+
+ for (x = minx; x <= maxx; x++)
+ {
+ if (cx1 + eo1 < 0 ||
+ cx2 + eo2 < 0 ||
+ cx3 + eo3 < 0)
+ {
+ /* do nothing */
+ if (in)
+ break;
+ }
+ else if (cx1 + ei1 > 0 &&
+ cx2 + ei2 > 0 &&
+ cx3 + ei3 > 0)
+ {
+ in = 1;
+ /* triangle covers the whole tile- shade whole tile */
+ lp_scene_bin_command( scene, x, y,
+ lp_rast_shade_tile,
+ lp_rast_arg_inputs(&tri->inputs) );
+ }
+ else
+ {
+ in = 1;
+ /* shade partial tile */
+ lp_scene_bin_command( scene, x, y,
+ lp_rast_triangle,
+ lp_rast_arg_triangle(tri) );
+ }
+
+ /* Iterate cx values across the region:
+ */
+ cx1 += xstep1;
+ cx2 += xstep2;
+ cx3 += xstep3;
+ }
+
+ /* Iterate c values down the region:
+ */
+ c1 += ystep1;
+ c2 += ystep2;
+ c3 += ystep3;
+ }
+ }
+}
+
+static void triangle_cw( struct setup_context *setup,
+ const float (*v0)[4],
+ const float (*v1)[4],
+ const float (*v2)[4] )
+{
+ do_triangle_ccw( setup, v1, v0, v2, !setup->ccw_is_frontface );
+}
+
+static void triangle_ccw( struct setup_context *setup,
+ const float (*v0)[4],
+ const float (*v1)[4],
+ const float (*v2)[4] )
+{
+ do_triangle_ccw( setup, v0, v1, v2, setup->ccw_is_frontface );
+}
+
+static void triangle_both( struct setup_context *setup,
+ const float (*v0)[4],
+ const float (*v1)[4],
+ const float (*v2)[4] )
+{
+ /* edge vectors e = v0 - v2, f = v1 - v2 */
+ const float ex = v0[0][0] - v2[0][0];
+ const float ey = v0[0][1] - v2[0][1];
+ const float fx = v1[0][0] - v2[0][0];
+ const float fy = v1[0][1] - v2[0][1];
+
+ /* det = cross(e,f).z */
+ if (ex * fy - ey * fx < 0)
+ triangle_ccw( setup, v0, v1, v2 );
+ else
+ triangle_cw( setup, v0, v1, v2 );
+}
+
+static void triangle_nop( struct setup_context *setup,
+ const float (*v0)[4],
+ const float (*v1)[4],
+ const float (*v2)[4] )
+{
+}
+
+
+void
+lp_setup_choose_triangle( struct setup_context *setup )
+{
+ switch (setup->cullmode) {
+ case PIPE_WINDING_NONE:
+ setup->triangle = triangle_both;
+ break;
+ case PIPE_WINDING_CCW:
+ setup->triangle = triangle_cw;
+ break;
+ case PIPE_WINDING_CW:
+ setup->triangle = triangle_ccw;
+ break;
+ default:
+ setup->triangle = triangle_nop;
+ break;
+ }
+}
+
+
diff --git a/src/gallium/drivers/llvmpipe/lp_setup_vbuf.c b/src/gallium/drivers/llvmpipe/lp_setup_vbuf.c
new file mode 100644
index 0000000000..42c30af5ba
--- /dev/null
+++ b/src/gallium/drivers/llvmpipe/lp_setup_vbuf.c
@@ -0,0 +1,520 @@
+/**************************************************************************
+ *
+ * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * 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 TUNGSTEN GRAPHICS 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.
+ *
+ **************************************************************************/
+
+/**
+ * Interface between 'draw' module's output and the llvmpipe rasterizer/setup
+ * code. When the 'draw' module has finished filling a vertex buffer, the
+ * draw_arrays() functions below will be called. Loop over the vertices and
+ * call the point/line/tri setup functions.
+ *
+ * Authors
+ * Brian Paul
+ */
+
+
+#include "lp_setup_context.h"
+#include "draw/draw_context.h"
+#include "draw/draw_vbuf.h"
+#include "draw/draw_vertex.h"
+#include "util/u_memory.h"
+#include "util/u_prim.h"
+
+
+#define LP_MAX_VBUF_INDEXES 1024
+#define LP_MAX_VBUF_SIZE 4096
+
+
+
+/** cast wrapper */
+static struct setup_context *
+setup_context(struct vbuf_render *vbr)
+{
+ return (struct setup_context *) vbr;
+}
+
+
+
+static const struct vertex_info *
+lp_setup_get_vertex_info(struct vbuf_render *vbr)
+{
+ struct setup_context *setup = setup_context(vbr);
+ return setup->vertex_info;
+}
+
+
+static boolean
+lp_setup_allocate_vertices(struct vbuf_render *vbr,
+ ushort vertex_size, ushort nr_vertices)
+{
+ struct setup_context *setup = setup_context(vbr);
+ unsigned size = vertex_size * nr_vertices;
+
+ if (setup->vertex_buffer_size < size) {
+ align_free(setup->vertex_buffer);
+ setup->vertex_buffer = align_malloc(size, 16);
+ setup->vertex_buffer_size = size;
+ }
+
+ setup->vertex_size = vertex_size;
+ setup->nr_vertices = nr_vertices;
+
+ return setup->vertex_buffer != NULL;
+}
+
+static void
+lp_setup_release_vertices(struct vbuf_render *vbr)
+{
+ /* keep the old allocation for next time */
+}
+
+static void *
+lp_setup_map_vertices(struct vbuf_render *vbr)
+{
+ struct setup_context *setup = setup_context(vbr);
+ return setup->vertex_buffer;
+}
+
+static void
+lp_setup_unmap_vertices(struct vbuf_render *vbr,
+ ushort min_index,
+ ushort max_index )
+{
+ struct setup_context *setup = setup_context(vbr);
+ assert( setup->vertex_buffer_size >= (max_index+1) * setup->vertex_size );
+ /* do nothing */
+}
+
+
+static boolean
+lp_setup_set_primitive(struct vbuf_render *vbr, unsigned prim)
+{
+ setup_context(vbr)->prim = prim;
+ return TRUE;
+}
+
+typedef const float (*const_float4_ptr)[4];
+
+static INLINE const_float4_ptr get_vert( const void *vertex_buffer,
+ int index,
+ int stride )
+{
+ return (const_float4_ptr)((char *)vertex_buffer + index * stride);
+}
+
+/**
+ * draw elements / indexed primitives
+ */
+static void
+lp_setup_draw(struct vbuf_render *vbr, const ushort *indices, uint nr)
+{
+ struct setup_context *setup = setup_context(vbr);
+ const unsigned stride = setup->vertex_info->size * sizeof(float);
+ const void *vertex_buffer = setup->vertex_buffer;
+ unsigned i;
+
+ lp_setup_update_state(setup);
+
+ switch (setup->prim) {
+ case PIPE_PRIM_POINTS:
+ for (i = 0; i < nr; i++) {
+ setup->point( setup,
+ get_vert(vertex_buffer, indices[i-0], stride) );
+ }
+ break;
+
+ case PIPE_PRIM_LINES:
+ for (i = 1; i < nr; i += 2) {
+ setup->line( setup,
+ get_vert(vertex_buffer, indices[i-1], stride),
+ get_vert(vertex_buffer, indices[i-0], stride) );
+ }
+ break;
+
+ case PIPE_PRIM_LINE_STRIP:
+ for (i = 1; i < nr; i ++) {
+ setup->line( setup,
+ get_vert(vertex_buffer, indices[i-1], stride),
+ get_vert(vertex_buffer, indices[i-0], stride) );
+ }
+ break;
+
+ case PIPE_PRIM_LINE_LOOP:
+ for (i = 1; i < nr; i ++) {
+ setup->line( setup,
+ get_vert(vertex_buffer, indices[i-1], stride),
+ get_vert(vertex_buffer, indices[i-0], stride) );
+ }
+ if (nr) {
+ setup->line( setup,
+ get_vert(vertex_buffer, indices[nr-1], stride),
+ get_vert(vertex_buffer, indices[0], stride) );
+ }
+ break;
+
+ case PIPE_PRIM_TRIANGLES:
+ if (setup->flatshade_first) {
+ for (i = 2; i < nr; i += 3) {
+ setup->triangle( setup,
+ get_vert(vertex_buffer, indices[i-1], stride),
+ get_vert(vertex_buffer, indices[i-0], stride),
+ get_vert(vertex_buffer, indices[i-2], stride) );
+ }
+ }
+ else {
+ for (i = 2; i < nr; i += 3) {
+ setup->triangle( setup,
+ get_vert(vertex_buffer, indices[i-2], stride),
+ get_vert(vertex_buffer, indices[i-1], stride),
+ get_vert(vertex_buffer, indices[i-0], stride) );
+ }
+ }
+ break;
+
+ case PIPE_PRIM_TRIANGLE_STRIP:
+ if (setup->flatshade_first) {
+ for (i = 2; i < nr; i += 1) {
+ setup->triangle( setup,
+ get_vert(vertex_buffer, indices[i+(i&1)-1], stride),
+ get_vert(vertex_buffer, indices[i-(i&1)], stride),
+ get_vert(vertex_buffer, indices[i-2], stride) );
+ }
+ }
+ else {
+ for (i = 2; i < nr; i += 1) {
+ setup->triangle( setup,
+ get_vert(vertex_buffer, indices[i+(i&1)-2], stride),
+ get_vert(vertex_buffer, indices[i-(i&1)-1], stride),
+ get_vert(vertex_buffer, indices[i-0], stride) );
+ }
+ }
+ break;
+
+ case PIPE_PRIM_TRIANGLE_FAN:
+ if (setup->flatshade_first) {
+ for (i = 2; i < nr; i += 1) {
+ setup->triangle( setup,
+ get_vert(vertex_buffer, indices[i-0], stride),
+ get_vert(vertex_buffer, indices[0], stride),
+ get_vert(vertex_buffer, indices[i-1], stride) );
+ }
+ }
+ else {
+ for (i = 2; i < nr; i += 1) {
+ setup->triangle( setup,
+ get_vert(vertex_buffer, indices[0], stride),
+ get_vert(vertex_buffer, indices[i-1], stride),
+ get_vert(vertex_buffer, indices[i-0], stride) );
+ }
+ }
+ break;
+
+ case PIPE_PRIM_QUADS:
+ if (setup->flatshade_first) {
+ for (i = 3; i < nr; i += 4) {
+ setup->triangle( setup,
+ get_vert(vertex_buffer, indices[i-2], stride),
+ get_vert(vertex_buffer, indices[i-1], stride),
+ get_vert(vertex_buffer, indices[i-3], stride) );
+ setup->triangle( setup,
+ get_vert(vertex_buffer, indices[i-1], stride),
+ get_vert(vertex_buffer, indices[i-0], stride),
+ get_vert(vertex_buffer, indices[i-3], stride) );
+ }
+ }
+ else {
+ for (i = 3; i < nr; i += 4) {
+ setup->triangle( setup,
+ get_vert(vertex_buffer, indices[i-3], stride),
+ get_vert(vertex_buffer, indices[i-2], stride),
+ get_vert(vertex_buffer, indices[i-0], stride) );
+
+ setup->triangle( setup,
+ get_vert(vertex_buffer, indices[i-2], stride),
+ get_vert(vertex_buffer, indices[i-1], stride),
+ get_vert(vertex_buffer, indices[i-0], stride) );
+ }
+ }
+ break;
+
+ case PIPE_PRIM_QUAD_STRIP:
+ if (setup->flatshade_first) {
+ for (i = 3; i < nr; i += 2) {
+ setup->triangle( setup,
+ get_vert(vertex_buffer, indices[i-0], stride),
+ get_vert(vertex_buffer, indices[i-1], stride),
+ get_vert(vertex_buffer, indices[i-3], stride));
+ setup->triangle( setup,
+ get_vert(vertex_buffer, indices[i-2], stride),
+ get_vert(vertex_buffer, indices[i-0], stride),
+ get_vert(vertex_buffer, indices[i-3], stride) );
+ }
+ }
+ else {
+ for (i = 3; i < nr; i += 2) {
+ setup->triangle( setup,
+ get_vert(vertex_buffer, indices[i-3], stride),
+ get_vert(vertex_buffer, indices[i-2], stride),
+ get_vert(vertex_buffer, indices[i-0], stride) );
+ setup->triangle( setup,
+ get_vert(vertex_buffer, indices[i-1], stride),
+ get_vert(vertex_buffer, indices[i-3], stride),
+ get_vert(vertex_buffer, indices[i-0], stride) );
+ }
+ }
+ break;
+
+ case PIPE_PRIM_POLYGON:
+ /* Almost same as tri fan but the _first_ vertex specifies the flat
+ * shading color. Note that the first polygon vertex is passed as
+ * the last triangle vertex here.
+ * flatshade_first state makes no difference.
+ */
+ for (i = 2; i < nr; i += 1) {
+ setup->triangle( setup,
+ get_vert(vertex_buffer, indices[i-0], stride),
+ get_vert(vertex_buffer, indices[i-1], stride),
+ get_vert(vertex_buffer, indices[0], stride) );
+ }
+ break;
+
+ default:
+ assert(0);
+ }
+}
+
+
+/**
+ * This function is hit when the draw module is working in pass-through mode.
+ * It's up to us to convert the vertex array into point/line/tri prims.
+ */
+static void
+lp_setup_draw_arrays(struct vbuf_render *vbr, uint start, uint nr)
+{
+ struct setup_context *setup = setup_context(vbr);
+ const unsigned stride = setup->vertex_info->size * sizeof(float);
+ const void *vertex_buffer =
+ (void *) get_vert(setup->vertex_buffer, start, stride);
+ unsigned i;
+
+ lp_setup_update_state(setup);
+
+ switch (setup->prim) {
+ case PIPE_PRIM_POINTS:
+ for (i = 0; i < nr; i++) {
+ setup->point( setup,
+ get_vert(vertex_buffer, i-0, stride) );
+ }
+ break;
+
+ case PIPE_PRIM_LINES:
+ for (i = 1; i < nr; i += 2) {
+ setup->line( setup,
+ get_vert(vertex_buffer, i-1, stride),
+ get_vert(vertex_buffer, i-0, stride) );
+ }
+ break;
+
+ case PIPE_PRIM_LINE_STRIP:
+ for (i = 1; i < nr; i ++) {
+ setup->line( setup,
+ get_vert(vertex_buffer, i-1, stride),
+ get_vert(vertex_buffer, i-0, stride) );
+ }
+ break;
+
+ case PIPE_PRIM_LINE_LOOP:
+ for (i = 1; i < nr; i ++) {
+ setup->line( setup,
+ get_vert(vertex_buffer, i-1, stride),
+ get_vert(vertex_buffer, i-0, stride) );
+ }
+ if (nr) {
+ setup->line( setup,
+ get_vert(vertex_buffer, nr-1, stride),
+ get_vert(vertex_buffer, 0, stride) );
+ }
+ break;
+
+ case PIPE_PRIM_TRIANGLES:
+ if (setup->flatshade_first) {
+ for (i = 2; i < nr; i += 3) {
+ setup->triangle( setup,
+ get_vert(vertex_buffer, i-1, stride),
+ get_vert(vertex_buffer, i-0, stride),
+ get_vert(vertex_buffer, i-2, stride) );
+ }
+ }
+ else {
+ for (i = 2; i < nr; i += 3) {
+ setup->triangle( setup,
+ get_vert(vertex_buffer, i-2, stride),
+ get_vert(vertex_buffer, i-1, stride),
+ get_vert(vertex_buffer, i-0, stride) );
+ }
+ }
+ break;
+
+ case PIPE_PRIM_TRIANGLE_STRIP:
+ if (setup->flatshade_first) {
+ for (i = 2; i < nr; i++) {
+ setup->triangle( setup,
+ get_vert(vertex_buffer, i+(i&1)-1, stride),
+ get_vert(vertex_buffer, i-(i&1), stride),
+ get_vert(vertex_buffer, i-2, stride) );
+ }
+ }
+ else {
+ for (i = 2; i < nr; i++) {
+ setup->triangle( setup,
+ get_vert(vertex_buffer, i+(i&1)-2, stride),
+ get_vert(vertex_buffer, i-(i&1)-1, stride),
+ get_vert(vertex_buffer, i-0, stride) );
+ }
+ }
+ break;
+
+ case PIPE_PRIM_TRIANGLE_FAN:
+ if (setup->flatshade_first) {
+ for (i = 2; i < nr; i += 1) {
+ setup->triangle( setup,
+ get_vert(vertex_buffer, i-0, stride),
+ get_vert(vertex_buffer, 0, stride),
+ get_vert(vertex_buffer, i-1, stride) );
+ }
+ }
+ else {
+ for (i = 2; i < nr; i += 1) {
+ setup->triangle( setup,
+ get_vert(vertex_buffer, 0, stride),
+ get_vert(vertex_buffer, i-1, stride),
+ get_vert(vertex_buffer, i-0, stride) );
+ }
+ }
+ break;
+
+ case PIPE_PRIM_QUADS:
+ if (setup->flatshade_first) {
+ for (i = 3; i < nr; i += 4) {
+ setup->triangle( setup,
+ get_vert(vertex_buffer, i-2, stride),
+ get_vert(vertex_buffer, i-1, stride),
+ get_vert(vertex_buffer, i-3, stride) );
+ setup->triangle( setup,
+ get_vert(vertex_buffer, i-1, stride),
+ get_vert(vertex_buffer, i-0, stride),
+ get_vert(vertex_buffer, i-3, stride) );
+ }
+ }
+ else {
+ for (i = 3; i < nr; i += 4) {
+ setup->triangle( setup,
+ get_vert(vertex_buffer, i-3, stride),
+ get_vert(vertex_buffer, i-2, stride),
+ get_vert(vertex_buffer, i-0, stride) );
+ setup->triangle( setup,
+ get_vert(vertex_buffer, i-2, stride),
+ get_vert(vertex_buffer, i-1, stride),
+ get_vert(vertex_buffer, i-0, stride) );
+ }
+ }
+ break;
+
+ case PIPE_PRIM_QUAD_STRIP:
+ if (setup->flatshade_first) {
+ for (i = 3; i < nr; i += 2) {
+ setup->triangle( setup,
+ get_vert(vertex_buffer, i-0, stride),
+ get_vert(vertex_buffer, i-1, stride),
+ get_vert(vertex_buffer, i-3, stride) );
+ setup->triangle( setup,
+
+ get_vert(vertex_buffer, i-2, stride),
+ get_vert(vertex_buffer, i-0, stride),
+ get_vert(vertex_buffer, i-3, stride) );
+ }
+ }
+ else {
+ for (i = 3; i < nr; i += 2) {
+ setup->triangle( setup,
+ get_vert(vertex_buffer, i-3, stride),
+ get_vert(vertex_buffer, i-2, stride),
+ get_vert(vertex_buffer, i-0, stride) );
+ setup->triangle( setup,
+ get_vert(vertex_buffer, i-1, stride),
+ get_vert(vertex_buffer, i-3, stride),
+ get_vert(vertex_buffer, i-0, stride) );
+ }
+ }
+ break;
+
+ case PIPE_PRIM_POLYGON:
+ /* Almost same as tri fan but the _first_ vertex specifies the flat
+ * shading color. Note that the first polygon vertex is passed as
+ * the last triangle vertex here.
+ * flatshade_first state makes no difference.
+ */
+ for (i = 2; i < nr; i += 1) {
+ setup->triangle( setup,
+ get_vert(vertex_buffer, i-1, stride),
+ get_vert(vertex_buffer, i-0, stride),
+ get_vert(vertex_buffer, 0, stride) );
+ }
+ break;
+
+ default:
+ assert(0);
+ }
+}
+
+
+
+static void
+lp_setup_vbuf_destroy(struct vbuf_render *vbr)
+{
+ lp_setup_destroy(setup_context(vbr));
+}
+
+
+/**
+ * Create the post-transform vertex handler for the given context.
+ */
+void
+lp_setup_init_vbuf(struct setup_context *setup)
+{
+ setup->base.max_indices = LP_MAX_VBUF_INDEXES;
+ setup->base.max_vertex_buffer_bytes = LP_MAX_VBUF_SIZE;
+
+ setup->base.get_vertex_info = lp_setup_get_vertex_info;
+ setup->base.allocate_vertices = lp_setup_allocate_vertices;
+ setup->base.map_vertices = lp_setup_map_vertices;
+ setup->base.unmap_vertices = lp_setup_unmap_vertices;
+ setup->base.set_primitive = lp_setup_set_primitive;
+ setup->base.draw = lp_setup_draw;
+ setup->base.draw_arrays = lp_setup_draw_arrays;
+ setup->base.release_vertices = lp_setup_release_vertices;
+ setup->base.destroy = lp_setup_vbuf_destroy;
+}
diff --git a/src/gallium/drivers/llvmpipe/lp_state.h b/src/gallium/drivers/llvmpipe/lp_state.h
index 7020da145f..25d1353674 100644
--- a/src/gallium/drivers/llvmpipe/lp_state.h
+++ b/src/gallium/drivers/llvmpipe/lp_state.h
@@ -54,6 +54,7 @@
#define LP_NEW_VERTEX 0x1000
#define LP_NEW_VS 0x2000
#define LP_NEW_QUERY 0x4000
+#define LP_NEW_BLEND_COLOR 0x8000
struct vertex_info;
@@ -212,23 +213,10 @@ llvmpipe_draw_range_elements(struct pipe_context *pipe,
unsigned mode, unsigned start, unsigned count);
void
-llvmpipe_map_transfers(struct llvmpipe_context *lp);
-
-void
-llvmpipe_unmap_transfers(struct llvmpipe_context *lp);
-
-void
llvmpipe_map_texture_surfaces(struct llvmpipe_context *lp);
void
llvmpipe_unmap_texture_surfaces(struct llvmpipe_context *lp);
-struct vertex_info *
-llvmpipe_get_vertex_info(struct llvmpipe_context *llvmpipe);
-
-struct vertex_info *
-llvmpipe_get_vbuf_vertex_info(struct llvmpipe_context *llvmpipe);
-
-
#endif
diff --git a/src/gallium/drivers/llvmpipe/lp_state_blend.c b/src/gallium/drivers/llvmpipe/lp_state_blend.c
index a94cd05ef2..a10c5918df 100644
--- a/src/gallium/drivers/llvmpipe/lp_state_blend.c
+++ b/src/gallium/drivers/llvmpipe/lp_state_blend.c
@@ -73,7 +73,12 @@ void llvmpipe_set_blend_color( struct pipe_context *pipe,
const struct pipe_blend_color *blend_color )
{
struct llvmpipe_context *llvmpipe = llvmpipe_context(pipe);
- unsigned i, j;
+
+ if(!blend_color)
+ return;
+
+ if(memcmp(&llvmpipe->blend_color, blend_color, sizeof *blend_color) == 0)
+ return;
if(memcmp(&llvmpipe->blend_color, blend_color, sizeof *blend_color) == 0)
return;
@@ -82,13 +87,7 @@ void llvmpipe_set_blend_color( struct pipe_context *pipe,
memcpy(&llvmpipe->blend_color, blend_color, sizeof *blend_color);
- if(!llvmpipe->jit_context.blend_color)
- llvmpipe->jit_context.blend_color = align_malloc(4 * 16, 16);
- for (i = 0; i < 4; ++i) {
- uint8_t c = float_to_ubyte(blend_color->color[i]);
- for (j = 0; j < 16; ++j)
- llvmpipe->jit_context.blend_color[i*16 + j] = c;
- }
+ llvmpipe->dirty |= LP_NEW_BLEND_COLOR;
}
@@ -117,9 +116,6 @@ llvmpipe_bind_depth_stencil_state(struct pipe_context *pipe,
llvmpipe->depth_stencil = depth_stencil;
- if(llvmpipe->depth_stencil)
- llvmpipe->jit_context.alpha_ref_value = llvmpipe->depth_stencil->alpha.ref_value;
-
llvmpipe->dirty |= LP_NEW_DEPTH_STENCIL_ALPHA;
}
diff --git a/src/gallium/drivers/llvmpipe/lp_state_derived.c b/src/gallium/drivers/llvmpipe/lp_state_derived.c
index 6c1ef6bc42..78d046985b 100644
--- a/src/gallium/drivers/llvmpipe/lp_state_derived.c
+++ b/src/gallium/drivers/llvmpipe/lp_state_derived.c
@@ -33,130 +33,108 @@
#include "draw/draw_private.h"
#include "lp_context.h"
#include "lp_screen.h"
-#include "lp_tex_cache.h"
+#include "lp_setup.h"
#include "lp_state.h"
-/**
- * Mark the current vertex layout as "invalid".
- * We'll validate the vertex layout later, when we start to actually
- * render a point or line or tri.
- */
-static void
-invalidate_vertex_layout(struct llvmpipe_context *llvmpipe)
-{
- llvmpipe->vertex_info.num_attribs = 0;
-}
-
/**
* The vertex info describes how to convert the post-transformed vertices
* (simple float[][4]) used by the 'draw' module into vertices for
* rasterization.
*
- * This function validates the vertex layout and returns a pointer to a
- * vertex_info object.
+ * This function validates the vertex layout.
*/
-struct vertex_info *
-llvmpipe_get_vertex_info(struct llvmpipe_context *llvmpipe)
+static void
+compute_vertex_info(struct llvmpipe_context *llvmpipe)
{
+ const struct lp_fragment_shader *lpfs = llvmpipe->fs;
struct vertex_info *vinfo = &llvmpipe->vertex_info;
+ const uint num = draw_num_shader_outputs(llvmpipe->draw);
+ uint i;
- if (vinfo->num_attribs == 0) {
- /* compute vertex layout now */
- const struct lp_fragment_shader *lpfs = llvmpipe->fs;
- struct vertex_info *vinfo_vbuf = &llvmpipe->vertex_info_vbuf;
- const uint num = draw_current_shader_outputs(llvmpipe->draw);
- uint i;
+ /* Tell setup to tell the draw module to simply emit the whole
+ * post-xform vertex as-is.
+ *
+ * Not really sure if this is the best approach.
+ */
+ vinfo->num_attribs = 0;
+ for (i = 0; i < num; i++) {
+ draw_emit_vertex_attr(vinfo, EMIT_4F, INTERP_PERSPECTIVE, i);
+ }
+ draw_compute_vertex_size(vinfo);
- /* Tell draw_vbuf to simply emit the whole post-xform vertex
- * as-is. No longer any need to try and emit draw vertex_header
- * info.
- */
- vinfo_vbuf->num_attribs = 0;
- for (i = 0; i < num; i++) {
- draw_emit_vertex_attr(vinfo_vbuf, EMIT_4F, INTERP_PERSPECTIVE, i);
- }
- draw_compute_vertex_size(vinfo_vbuf);
- /*
- * Loop over fragment shader inputs, searching for the matching output
- * from the vertex shader.
- */
- vinfo->num_attribs = 0;
- for (i = 0; i < lpfs->info.num_inputs; i++) {
- int src;
- enum interp_mode interp;
+ lp_setup_set_vertex_info(llvmpipe->setup, vinfo);
- switch (lpfs->info.input_interpolate[i]) {
- case TGSI_INTERPOLATE_CONSTANT:
- interp = INTERP_CONSTANT;
- break;
- case TGSI_INTERPOLATE_LINEAR:
- interp = INTERP_LINEAR;
- break;
- case TGSI_INTERPOLATE_PERSPECTIVE:
- interp = INTERP_PERSPECTIVE;
- break;
- default:
- assert(0);
- interp = INTERP_LINEAR;
- }
+/*
+ llvmpipe->psize_slot = draw_find_vs_output(llvmpipe->draw,
+ TGSI_SEMANTIC_PSIZE, 0);
+*/
+ /* Now match FS inputs against emitted vertex data. It's also
+ * entirely possible to just have a fixed layout for FS input,
+ * determined by the fragment shader itself, and adjust the draw
+ * outputs to match that.
+ */
+ {
+ struct lp_shader_input inputs[PIPE_MAX_SHADER_INPUTS];
+
+ for (i = 0; i < lpfs->info.num_inputs; i++) {
+
+ /* This can be precomputed, except for flatshade:
+ */
switch (lpfs->info.input_semantic_name[i]) {
+ case TGSI_SEMANTIC_FACE:
+ inputs[i].interp = LP_INTERP_FACING;
+ break;
case TGSI_SEMANTIC_POSITION:
- interp = INTERP_POS;
+ inputs[i].interp = LP_INTERP_POSITION;
break;
-
case TGSI_SEMANTIC_COLOR:
- if (llvmpipe->rasterizer->flatshade) {
- interp = INTERP_CONSTANT;
- }
+ /* Colors are linearly interpolated in the fragment shader
+ * even when flatshading is active. This just tells the
+ * setup module to use coefficients with ddx==0 and
+ * ddy==0.
+ */
+ if (llvmpipe->rasterizer->flatshade)
+ inputs[i].interp = LP_INTERP_CONSTANT;
+ else
+ inputs[i].interp = LP_INTERP_LINEAR;
break;
- }
- /* this includes texcoords and varying vars */
- src = draw_find_shader_output(llvmpipe->draw,
- lpfs->info.input_semantic_name[i],
- lpfs->info.input_semantic_index[i]);
- draw_emit_vertex_attr(vinfo, EMIT_4F, interp, src);
- }
+ default:
+ switch (lpfs->info.input_interpolate[i]) {
+ case TGSI_INTERPOLATE_CONSTANT:
+ inputs[i].interp = LP_INTERP_CONSTANT;
+ break;
+ case TGSI_INTERPOLATE_LINEAR:
+ inputs[i].interp = LP_INTERP_LINEAR;
+ break;
+ case TGSI_INTERPOLATE_PERSPECTIVE:
+ inputs[i].interp = LP_INTERP_PERSPECTIVE;
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ }
- llvmpipe->psize_slot = draw_find_shader_output(llvmpipe->draw,
- TGSI_SEMANTIC_PSIZE, 0);
- if (llvmpipe->psize_slot > 0) {
- draw_emit_vertex_attr(vinfo, EMIT_4F, INTERP_CONSTANT,
- llvmpipe->psize_slot);
+ /* Search for each input in current vs output:
+ */
+ inputs[i].src_index =
+ draw_find_shader_output(llvmpipe->draw,
+ lpfs->info.input_semantic_name[i],
+ lpfs->info.input_semantic_index[i]);
}
- draw_compute_vertex_size(vinfo);
+ lp_setup_set_fs_inputs(llvmpipe->setup,
+ inputs,
+ lpfs->info.num_inputs);
}
-
- return vinfo;
}
-/**
- * Called from vbuf module.
- *
- * Note that there's actually two different vertex layouts in llvmpipe.
- *
- * The normal one is computed in llvmpipe_get_vertex_info() above and is
- * used by the point/line/tri "setup" code.
- *
- * The other one (this one) is only used by the vbuf module (which is
- * not normally used by default but used in testing). For the vbuf module,
- * we basically want to pass-through the draw module's vertex layout as-is.
- * When the llvmpipe vbuf code begins drawing, the normal vertex layout
- * will come into play again.
- */
-struct vertex_info *
-llvmpipe_get_vbuf_vertex_info(struct llvmpipe_context *llvmpipe)
-{
- (void) llvmpipe_get_vertex_info(llvmpipe);
- return &llvmpipe->vertex_info_vbuf;
-}
-
/**
* Recompute cliprect from scissor bounds, scissor enable and surface size.
@@ -206,15 +184,10 @@ void llvmpipe_update_derived( struct llvmpipe_context *llvmpipe )
llvmpipe->dirty |= LP_NEW_TEXTURE;
}
- if (llvmpipe->dirty & (LP_NEW_SAMPLER |
- LP_NEW_TEXTURE)) {
- /* TODO */
- }
-
if (llvmpipe->dirty & (LP_NEW_RASTERIZER |
LP_NEW_FS |
LP_NEW_VS))
- invalidate_vertex_layout( llvmpipe );
+ compute_vertex_info( llvmpipe );
if (llvmpipe->dirty & (LP_NEW_SCISSOR |
LP_NEW_RASTERIZER |
@@ -228,6 +201,23 @@ void llvmpipe_update_derived( struct llvmpipe_context *llvmpipe )
LP_NEW_TEXTURE))
llvmpipe_update_fs( llvmpipe );
+ if (llvmpipe->dirty & LP_NEW_BLEND_COLOR)
+ lp_setup_set_blend_color(llvmpipe->setup,
+ &llvmpipe->blend_color);
+
+ if (llvmpipe->dirty & LP_NEW_DEPTH_STENCIL_ALPHA)
+ lp_setup_set_alpha_ref_value(llvmpipe->setup,
+ llvmpipe->depth_stencil->alpha.ref_value);
+
+ if (llvmpipe->dirty & LP_NEW_CONSTANTS)
+ lp_setup_set_fs_constants(llvmpipe->setup,
+ llvmpipe->constants[PIPE_SHADER_FRAGMENT].buffer);
+
+ if (llvmpipe->dirty & LP_NEW_TEXTURE)
+ lp_setup_set_sampler_textures(llvmpipe->setup,
+ llvmpipe->num_textures,
+ llvmpipe->texture);
llvmpipe->dirty = 0;
}
+
diff --git a/src/gallium/drivers/llvmpipe/lp_state_fs.c b/src/gallium/drivers/llvmpipe/lp_state_fs.c
index b73ca2d41e..3a669ba859 100644
--- a/src/gallium/drivers/llvmpipe/lp_state_fs.c
+++ b/src/gallium/drivers/llvmpipe/lp_state_fs.c
@@ -84,8 +84,8 @@
#include "lp_screen.h"
#include "lp_context.h"
#include "lp_buffer.h"
+#include "lp_setup.h"
#include "lp_state.h"
-#include "lp_quad.h"
#include "lp_tex_sample.h"
#include "lp_debug.h"
@@ -187,7 +187,93 @@ generate_depth(LLVMBuilderRef builder,
/**
+ * Generate the code to do inside/outside triangle testing for the
+ * four pixels in a 2x2 quad. This will set the four elements of the
+ * quad mask vector to 0 or ~0.
+ * \param i which quad of the quad group to test, in [0,3]
+ */
+static void
+generate_tri_edge_mask(LLVMBuilderRef builder,
+ unsigned i,
+ LLVMValueRef *mask, /* ivec4, out */
+ LLVMValueRef c0, /* int32 */
+ LLVMValueRef c1, /* int32 */
+ LLVMValueRef c2, /* int32 */
+ LLVMValueRef step0_ptr, /* ivec4 */
+ LLVMValueRef step1_ptr, /* ivec4 */
+ LLVMValueRef step2_ptr) /* ivec4 */
+{
+ /*
+ c0_vec = splat(c0)
+ c1_vec = splat(c1)
+ c2_vec = splat(c2)
+ m0_vec = step0_ptr[i] > c0_vec
+ m1_vec = step1_ptr[i] > c1_vec
+ m2_vec = step2_ptr[i] > c2_vec
+ mask = m0_vec & m1_vec & m2_vec
+ */
+ struct lp_type i32_type;
+ LLVMTypeRef i32vec4_type;
+
+ LLVMValueRef index;
+ LLVMValueRef c0_vec, c1_vec, c2_vec;
+ LLVMValueRef step0_vec, step1_vec, step2_vec;
+ LLVMValueRef m0_vec, m1_vec, m2_vec;
+ LLVMValueRef m;
+
+ assert(i < 4);
+
+ /* int32 vector type */
+ memset(&i32_type, 0, sizeof i32_type);
+ i32_type.floating = FALSE; /* values are integers */
+ i32_type.sign = TRUE; /* values are signed */
+ i32_type.norm = FALSE; /* values are not normalized */
+ i32_type.width = 32; /* 32-bit int values */
+ i32_type.length = 4; /* 4 elements per vector */
+
+ i32vec4_type = lp_build_int32_vec4_type();
+
+ /* c0_vec = {c0, c0, c0, c0}
+ * Note that we emit this code four times but LLVM optimizes away
+ * three instances of it.
+ */
+ c0_vec = lp_build_broadcast(builder, i32vec4_type, c0);
+ c1_vec = lp_build_broadcast(builder, i32vec4_type, c1);
+ c2_vec = lp_build_broadcast(builder, i32vec4_type, c2);
+
+ lp_build_name(c0_vec, "edgeconst0vec");
+ lp_build_name(c1_vec, "edgeconst1vec");
+ lp_build_name(c2_vec, "edgeconst2vec");
+
+ index = LLVMConstInt(LLVMInt32Type(), i, 0);
+ step0_vec = LLVMBuildLoad(builder, LLVMBuildGEP(builder, step0_ptr, &index, 1, ""), "");
+ step1_vec = LLVMBuildLoad(builder, LLVMBuildGEP(builder, step1_ptr, &index, 1, ""), "");
+ step2_vec = LLVMBuildLoad(builder, LLVMBuildGEP(builder, step2_ptr, &index, 1, ""), "");
+
+ lp_build_name(step0_vec, "step0vec");
+ lp_build_name(step1_vec, "step1vec");
+ lp_build_name(step2_vec, "step2vec");
+
+ m0_vec = lp_build_compare(builder, i32_type, PIPE_FUNC_GREATER, step0_vec, c0_vec);
+ m1_vec = lp_build_compare(builder, i32_type, PIPE_FUNC_GREATER, step1_vec, c1_vec);
+ m2_vec = lp_build_compare(builder, i32_type, PIPE_FUNC_GREATER, step2_vec, c2_vec);
+
+ m = LLVMBuildAnd(builder, m0_vec, m1_vec, "");
+ m = LLVMBuildAnd(builder, m, m2_vec, "");
+
+ lp_build_name(m, "inoutmaskvec");
+
+ *mask = m;
+
+ /*
+ * if mask = {0,0,0,0} skip quad
+ */
+}
+
+
+/**
* Generate the fragment shader, depth/stencil test, and alpha tests.
+ * \param i which quad in the tile, in range [0,3]
*/
static void
generate_fs(struct llvmpipe_context *lp,
@@ -201,7 +287,13 @@ generate_fs(struct llvmpipe_context *lp,
struct lp_build_sampler_soa *sampler,
LLVMValueRef *pmask,
LLVMValueRef *color,
- LLVMValueRef depth_ptr)
+ LLVMValueRef depth_ptr,
+ LLVMValueRef c0,
+ LLVMValueRef c1,
+ LLVMValueRef c2,
+ LLVMValueRef step0_ptr,
+ LLVMValueRef step1_ptr,
+ LLVMValueRef step2_ptr)
{
const struct tgsi_token *tokens = shader->base.tokens;
LLVMTypeRef elem_type;
@@ -216,6 +308,8 @@ generate_fs(struct llvmpipe_context *lp,
unsigned attrib;
unsigned chan;
+ assert(i < 4);
+
elem_type = lp_build_elem_type(type);
vec_type = lp_build_vec_type(type);
int_vec_type = lp_build_int_vec_type(type);
@@ -235,8 +329,14 @@ generate_fs(struct llvmpipe_context *lp,
}
lp_build_flow_scope_declare(flow, &z);
+ /* do triangle edge testing */
+ generate_tri_edge_mask(builder, i, pmask,
+ c0, c1, c2, step0_ptr, step1_ptr, step2_ptr);
+
+ /* 'mask' will control execution based on quad's pixel alive/killed state */
lp_build_mask_begin(&mask, flow, type, *pmask);
+
early_depth_test =
key->depth.enabled &&
!key->alpha.enabled &&
@@ -369,6 +469,9 @@ generate_blend(const struct pipe_blend_state *blend,
/**
* Generate the runtime callable function for the whole fragment pipeline.
+ * Note that the function which we generate operates on a block of 16
+ * pixels at at time. The block contains 2x2 quads. Each quad contains
+ * 2x2 pixels.
*/
static struct lp_fragment_shader_variant *
generate_fragment(struct llvmpipe_context *lp,
@@ -384,17 +487,18 @@ generate_fragment(struct llvmpipe_context *lp,
LLVMTypeRef fs_int_vec_type;
LLVMTypeRef blend_vec_type;
LLVMTypeRef blend_int_vec_type;
- LLVMTypeRef arg_types[9];
+ LLVMTypeRef arg_types[14];
LLVMTypeRef func_type;
+ LLVMTypeRef int32_vec4_type = lp_build_int32_vec4_type();
LLVMValueRef context_ptr;
LLVMValueRef x;
LLVMValueRef y;
LLVMValueRef a0_ptr;
LLVMValueRef dadx_ptr;
LLVMValueRef dady_ptr;
- LLVMValueRef mask_ptr;
LLVMValueRef color_ptr;
LLVMValueRef depth_ptr;
+ LLVMValueRef c0, c1, c2, step0_ptr, step1_ptr, step2_ptr;
LLVMBasicBlockRef block;
LLVMBuilderRef builder;
LLVMValueRef x0;
@@ -476,8 +580,8 @@ generate_fragment(struct llvmpipe_context *lp,
fs_type.sign = TRUE; /* values are signed */
fs_type.norm = FALSE; /* values are not limited to [0,1] or [-1,1] */
fs_type.width = 32; /* 32-bit float */
- fs_type.length = 4; /* 4 element per vector */
- num_fs = 4;
+ fs_type.length = 4; /* 4 elements per vector */
+ num_fs = 4; /* number of quads per block */
memset(&blend_type, 0, sizeof blend_type);
blend_type.floating = FALSE; /* values are integers */
@@ -504,9 +608,17 @@ generate_fragment(struct llvmpipe_context *lp,
arg_types[3] = LLVMPointerType(fs_elem_type, 0); /* a0 */
arg_types[4] = LLVMPointerType(fs_elem_type, 0); /* dadx */
arg_types[5] = LLVMPointerType(fs_elem_type, 0); /* dady */
- arg_types[6] = LLVMPointerType(fs_int_vec_type, 0); /* mask */
- arg_types[7] = LLVMPointerType(blend_vec_type, 0); /* color */
- arg_types[8] = LLVMPointerType(fs_int_vec_type, 0); /* depth */
+ arg_types[6] = LLVMPointerType(blend_vec_type, 0); /* color */
+ arg_types[7] = LLVMPointerType(fs_int_vec_type, 0); /* depth */
+ arg_types[8] = LLVMInt32Type(); /* c0 */
+ arg_types[9] = LLVMInt32Type(); /* c1 */
+ arg_types[10] = LLVMInt32Type(); /* c2 */
+ /* Note: the step arrays are built as int32[16] but we interpret
+ * them here as int32_vec4[4].
+ */
+ arg_types[11] = LLVMPointerType(int32_vec4_type, 0);/* step0 */
+ arg_types[12] = LLVMPointerType(int32_vec4_type, 0);/* step1 */
+ arg_types[13] = LLVMPointerType(int32_vec4_type, 0);/* step2 */
func_type = LLVMFunctionType(LLVMVoidType(), arg_types, Elements(arg_types), 0);
@@ -522,9 +634,14 @@ generate_fragment(struct llvmpipe_context *lp,
a0_ptr = LLVMGetParam(variant->function, 3);
dadx_ptr = LLVMGetParam(variant->function, 4);
dady_ptr = LLVMGetParam(variant->function, 5);
- mask_ptr = LLVMGetParam(variant->function, 6);
- color_ptr = LLVMGetParam(variant->function, 7);
- depth_ptr = LLVMGetParam(variant->function, 8);
+ color_ptr = LLVMGetParam(variant->function, 6);
+ depth_ptr = LLVMGetParam(variant->function, 7);
+ c0 = LLVMGetParam(variant->function, 8);
+ c1 = LLVMGetParam(variant->function, 9);
+ c2 = LLVMGetParam(variant->function, 10);
+ step0_ptr = LLVMGetParam(variant->function, 11);
+ step1_ptr = LLVMGetParam(variant->function, 12);
+ step2_ptr = LLVMGetParam(variant->function, 13);
lp_build_name(context_ptr, "context");
lp_build_name(x, "x");
@@ -532,9 +649,14 @@ generate_fragment(struct llvmpipe_context *lp,
lp_build_name(a0_ptr, "a0");
lp_build_name(dadx_ptr, "dadx");
lp_build_name(dady_ptr, "dady");
- lp_build_name(mask_ptr, "mask");
lp_build_name(color_ptr, "color");
lp_build_name(depth_ptr, "depth");
+ lp_build_name(c0, "c0");
+ lp_build_name(c1, "c1");
+ lp_build_name(c2, "c2");
+ lp_build_name(step0_ptr, "step0");
+ lp_build_name(step1_ptr, "step1");
+ lp_build_name(step2_ptr, "step2");
/*
* Function body
@@ -548,20 +670,20 @@ generate_fragment(struct llvmpipe_context *lp,
lp_build_interp_soa_init(&interp, shader->base.tokens, builder, fs_type,
a0_ptr, dadx_ptr, dady_ptr,
- x0, y0, 2, 0);
+ x0, y0);
/* code generated texture sampling */
sampler = lp_llvm_sampler_soa_create(key->sampler, context_ptr);
+ /* loop over quads in the block */
for(i = 0; i < num_fs; ++i) {
LLVMValueRef index = LLVMConstInt(LLVMInt32Type(), i, 0);
LLVMValueRef out_color[NUM_CHANNELS];
LLVMValueRef depth_ptr_i;
if(i != 0)
- lp_build_interp_soa_update(&interp);
+ lp_build_interp_soa_update(&interp, i);
- fs_mask[i] = LLVMBuildLoad(builder, LLVMBuildGEP(builder, mask_ptr, &index, 1, ""), "");
depth_ptr_i = LLVMBuildGEP(builder, depth_ptr, &index, 1, "");
generate_fs(lp, shader, key,
@@ -571,9 +693,11 @@ generate_fragment(struct llvmpipe_context *lp,
i,
&interp,
sampler,
- &fs_mask[i],
+ &fs_mask[i], /* output */
out_color,
- depth_ptr_i);
+ depth_ptr_i,
+ c0, c1, c2,
+ step0_ptr, step1_ptr, step2_ptr);
for(chan = 0; chan < NUM_CHANNELS; ++chan)
fs_out_color[chan][i] = out_color[chan];
@@ -724,15 +848,14 @@ llvmpipe_set_constant_buffer(struct pipe_context *pipe,
assert(shader < PIPE_SHADER_TYPES);
assert(index == 0);
+ if(llvmpipe->constants[shader].buffer == buffer)
+ return;
+
draw_flush(llvmpipe->draw);
/* note: reference counting */
pipe_buffer_reference(&llvmpipe->constants[shader].buffer, buffer);
- if(shader == PIPE_SHADER_FRAGMENT) {
- llvmpipe->jit_context.constants = data;
- }
-
if(shader == PIPE_SHADER_VERTEX) {
draw_set_mapped_constant_buffer(llvmpipe->draw, PIPE_SHADER_VERTEX,
data, size);
@@ -814,4 +937,7 @@ llvmpipe_update_fs(struct llvmpipe_context *lp)
variant = generate_fragment(lp, shader, &key);
shader->current = variant;
+
+ lp_setup_set_fs_function(lp->setup,
+ shader->current->jit_function);
}
diff --git a/src/gallium/drivers/llvmpipe/lp_state_rasterizer.c b/src/gallium/drivers/llvmpipe/lp_state_rasterizer.c
index aa3b5a3f91..7d4c310aae 100644
--- a/src/gallium/drivers/llvmpipe/lp_state_rasterizer.c
+++ b/src/gallium/drivers/llvmpipe/lp_state_rasterizer.c
@@ -29,6 +29,7 @@
#include "util/u_memory.h"
#include "lp_context.h"
#include "lp_state.h"
+#include "lp_setup.h"
#include "draw/draw_context.h"
@@ -53,6 +54,16 @@ void llvmpipe_bind_rasterizer_state(struct pipe_context *pipe,
llvmpipe->rasterizer = rasterizer;
+ /* Note: we can immediately set the triangle state here and
+ * not worry about binning because we handle culling during
+ * triangle setup, not when rasterizing the bins.
+ */
+ if (llvmpipe->rasterizer) {
+ lp_setup_set_triangle_state( llvmpipe->setup,
+ llvmpipe->rasterizer->cull_mode,
+ llvmpipe->rasterizer->front_winding == PIPE_WINDING_CCW );
+ }
+
llvmpipe->dirty |= LP_NEW_RASTERIZER;
}
diff --git a/src/gallium/drivers/llvmpipe/lp_state_sampler.c b/src/gallium/drivers/llvmpipe/lp_state_sampler.c
index d382f9ca87..976f81113f 100644
--- a/src/gallium/drivers/llvmpipe/lp_state_sampler.c
+++ b/src/gallium/drivers/llvmpipe/lp_state_sampler.c
@@ -37,7 +37,6 @@
#include "lp_context.h"
#include "lp_state.h"
#include "lp_texture.h"
-#include "lp_tex_cache.h"
#include "draw/draw_context.h"
@@ -125,17 +124,6 @@ llvmpipe_set_sampler_textures(struct pipe_context *pipe,
struct pipe_texture *tex = i < num ? texture[i] : NULL;
pipe_texture_reference(&llvmpipe->texture[i], tex);
- lp_tex_tile_cache_set_texture(llvmpipe->tex_cache[i], tex);
-
- if(tex) {
- struct llvmpipe_texture *lp_tex = llvmpipe_texture(tex);
- struct lp_jit_texture *jit_tex = &llvmpipe->jit_context.textures[i];
- jit_tex->width = tex->width0;
- jit_tex->height = tex->height0;
- jit_tex->stride = lp_tex->stride[0];
- if(!lp_tex->dt)
- jit_tex->data = lp_tex->data;
- }
}
llvmpipe->num_textures = num;
@@ -166,7 +154,6 @@ llvmpipe_set_vertex_sampler_textures(struct pipe_context *pipe,
struct pipe_texture *tex = i < num_textures ? textures[i] : NULL;
pipe_texture_reference(&llvmpipe->vertex_textures[i], tex);
- lp_tex_tile_cache_set_texture(llvmpipe->vertex_tex_cache[i], tex);
}
llvmpipe->num_vertex_textures = num_textures;
diff --git a/src/gallium/drivers/llvmpipe/lp_state_surface.c b/src/gallium/drivers/llvmpipe/lp_state_surface.c
index e37ff04f3d..0e9f03b90b 100644
--- a/src/gallium/drivers/llvmpipe/lp_state_surface.c
+++ b/src/gallium/drivers/llvmpipe/lp_state_surface.c
@@ -28,10 +28,12 @@
/* Authors: Keith Whitwell <keith@tungstengraphics.com>
*/
+#include "pipe/p_state.h"
+#include "util/u_surface.h"
#include "lp_context.h"
#include "lp_state.h"
#include "lp_surface.h"
-#include "lp_tile_cache.h"
+#include "lp_setup.h"
#include "draw/draw_context.h"
@@ -39,54 +41,19 @@
/**
- * XXX this might get moved someday
* Set the framebuffer surface info: color buffers, zbuffer, stencil buffer.
- * Here, we flush the old surfaces and update the tile cache to point to the new
- * surfaces.
*/
void
llvmpipe_set_framebuffer_state(struct pipe_context *pipe,
const struct pipe_framebuffer_state *fb)
{
struct llvmpipe_context *lp = llvmpipe_context(pipe);
- uint i;
- draw_flush(lp->draw);
+ boolean changed = !util_framebuffer_state_equal(&lp->framebuffer, fb);
- for (i = 0; i < PIPE_MAX_COLOR_BUFS; i++) {
- /* check if changing cbuf */
- if (lp->framebuffer.cbufs[i] != fb->cbufs[i]) {
- /* flush old */
- lp_tile_cache_map_transfers(lp->cbuf_cache[i]);
- lp_flush_tile_cache(lp->cbuf_cache[i]);
+ if (changed) {
- /* assign new */
- pipe_surface_reference(&lp->framebuffer.cbufs[i], fb->cbufs[i]);
-
- /* update cache */
- lp_tile_cache_set_surface(lp->cbuf_cache[i], fb->cbufs[i]);
- }
- }
-
- lp->framebuffer.nr_cbufs = fb->nr_cbufs;
-
- /* zbuf changing? */
- if (lp->framebuffer.zsbuf != fb->zsbuf) {
-
- if(lp->zsbuf_transfer) {
- struct pipe_screen *screen = pipe->screen;
-
- if(lp->zsbuf_map) {
- screen->transfer_unmap(screen, lp->zsbuf_transfer);
- lp->zsbuf_map = NULL;
- }
-
- screen->tex_transfer_destroy(lp->zsbuf_transfer);
- lp->zsbuf_transfer = NULL;
- }
-
- /* assign new */
- pipe_surface_reference(&lp->framebuffer.zsbuf, fb->zsbuf);
+ util_copy_framebuffer_state(&lp->framebuffer, fb);
/* Tell draw module how deep the Z/depth buffer is */
if (lp->framebuffer.zsbuf) {
@@ -103,10 +70,9 @@ llvmpipe_set_framebuffer_state(struct pipe_context *pipe,
}
draw_set_mrd(lp->draw, mrd);
}
- }
- lp->framebuffer.width = fb->width;
- lp->framebuffer.height = fb->height;
+ lp_setup_bind_framebuffer( lp->setup, &lp->framebuffer );
- lp->dirty |= LP_NEW_FRAMEBUFFER;
+ lp->dirty |= LP_NEW_FRAMEBUFFER;
+ }
}
diff --git a/src/gallium/drivers/llvmpipe/lp_tex_cache.c b/src/gallium/drivers/llvmpipe/lp_tex_cache.c
deleted file mode 100644
index a6d9a2c1ac..0000000000
--- a/src/gallium/drivers/llvmpipe/lp_tex_cache.c
+++ /dev/null
@@ -1,304 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
- * 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 TUNGSTEN GRAPHICS 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.
- *
- **************************************************************************/
-
-/**
- * Texture tile caching.
- *
- * Author:
- * Brian Paul
- */
-
-#include "pipe/p_inlines.h"
-#include "util/u_memory.h"
-#include "util/u_tile.h"
-#include "util/u_format.h"
-#include "util/u_math.h"
-#include "lp_context.h"
-#include "lp_surface.h"
-#include "lp_texture.h"
-#include "lp_tex_cache.h"
-
-
-
-/**
- * Return the position in the cache for the tile that contains win pos (x,y).
- * We currently use a direct mapped cache so this is like a hack key.
- * At some point we should investige something more sophisticated, like
- * a LRU replacement policy.
- */
-#define CACHE_POS(x, y) \
- (((x) + (y) * 5) % NUM_ENTRIES)
-
-
-
-/**
- * Is the tile at (x,y) in cleared state?
- */
-static INLINE uint
-is_clear_flag_set(const uint *bitvec, union tex_tile_address addr)
-{
- int pos, bit;
- pos = addr.bits.y * (MAX_TEX_WIDTH / TEX_TILE_SIZE) + addr.bits.x;
- assert(pos / 32 < (MAX_TEX_WIDTH / TEX_TILE_SIZE) * (MAX_TEX_HEIGHT / TEX_TILE_SIZE) / 32);
- bit = bitvec[pos / 32] & (1 << (pos & 31));
- return bit;
-}
-
-
-/**
- * Mark the tile at (x,y) as not cleared.
- */
-static INLINE void
-clear_clear_flag(uint *bitvec, union tex_tile_address addr)
-{
- int pos;
- pos = addr.bits.y * (MAX_TEX_WIDTH / TEX_TILE_SIZE) + addr.bits.x;
- assert(pos / 32 < (MAX_TEX_WIDTH / TEX_TILE_SIZE) * (MAX_TEX_HEIGHT / TEX_TILE_SIZE) / 32);
- bitvec[pos / 32] &= ~(1 << (pos & 31));
-}
-
-
-struct llvmpipe_tex_tile_cache *
-lp_create_tex_tile_cache( struct pipe_screen *screen )
-{
- struct llvmpipe_tex_tile_cache *tc;
- uint pos;
-
- tc = CALLOC_STRUCT( llvmpipe_tex_tile_cache );
- if (tc) {
- tc->screen = screen;
- for (pos = 0; pos < NUM_ENTRIES; pos++) {
- tc->entries[pos].addr.bits.invalid = 1;
- }
- tc->last_tile = &tc->entries[0]; /* any tile */
- }
- return tc;
-}
-
-
-void
-lp_destroy_tex_tile_cache(struct llvmpipe_tex_tile_cache *tc)
-{
- struct pipe_screen *screen;
- uint pos;
-
- for (pos = 0; pos < NUM_ENTRIES; pos++) {
- /*assert(tc->entries[pos].x < 0);*/
- }
- if (tc->transfer) {
- screen = tc->transfer->texture->screen;
- screen->tex_transfer_destroy(tc->transfer);
- }
- if (tc->tex_trans) {
- screen = tc->tex_trans->texture->screen;
- screen->tex_transfer_destroy(tc->tex_trans);
- }
-
- FREE( tc );
-}
-
-
-void
-lp_tex_tile_cache_map_transfers(struct llvmpipe_tex_tile_cache *tc)
-{
- if (tc->transfer && !tc->transfer_map)
- tc->transfer_map = tc->screen->transfer_map(tc->screen, tc->transfer);
-
- if (tc->tex_trans && !tc->tex_trans_map)
- tc->tex_trans_map = tc->screen->transfer_map(tc->screen, tc->tex_trans);
-}
-
-
-void
-lp_tex_tile_cache_unmap_transfers(struct llvmpipe_tex_tile_cache *tc)
-{
- if (tc->transfer_map) {
- tc->screen->transfer_unmap(tc->screen, tc->transfer);
- tc->transfer_map = NULL;
- }
-
- if (tc->tex_trans_map) {
- tc->screen->transfer_unmap(tc->screen, tc->tex_trans);
- tc->tex_trans_map = NULL;
- }
-}
-
-void
-lp_tex_tile_cache_validate_texture(struct llvmpipe_tex_tile_cache *tc)
-{
- if (tc->texture) {
- struct llvmpipe_texture *lpt = llvmpipe_texture(tc->texture);
- if (lpt->timestamp != tc->timestamp) {
- /* texture was modified, invalidate all cached tiles */
- uint i;
- for (i = 0; i < NUM_ENTRIES; i++) {
- tc->entries[i].addr.bits.invalid = 1;
- }
-
- tc->timestamp = lpt->timestamp;
- }
- }
-}
-
-/**
- * Specify the texture to cache.
- */
-void
-lp_tex_tile_cache_set_texture(struct llvmpipe_tex_tile_cache *tc,
- struct pipe_texture *texture)
-{
- uint i;
-
- assert(!tc->transfer);
-
- if (tc->texture != texture) {
- pipe_texture_reference(&tc->texture, texture);
-
- if (tc->tex_trans) {
- struct pipe_screen *screen = tc->tex_trans->texture->screen;
-
- if (tc->tex_trans_map) {
- screen->transfer_unmap(screen, tc->tex_trans);
- tc->tex_trans_map = NULL;
- }
-
- screen->tex_transfer_destroy(tc->tex_trans);
- tc->tex_trans = NULL;
- }
-
- /* mark as entries as invalid/empty */
- /* XXX we should try to avoid this when the teximage hasn't changed */
- for (i = 0; i < NUM_ENTRIES; i++) {
- tc->entries[i].addr.bits.invalid = 1;
- }
-
- tc->tex_face = -1; /* any invalid value here */
- }
-}
-
-
-/**
- * Given the texture face, level, zslice, x and y values, compute
- * the cache entry position/index where we'd hope to find the
- * cached texture tile.
- * This is basically a direct-map cache.
- * XXX There's probably lots of ways in which we can improve this.
- */
-static INLINE uint
-tex_cache_pos( union tex_tile_address addr )
-{
- uint entry = (addr.bits.x +
- addr.bits.y * 9 +
- addr.bits.z * 3 +
- addr.bits.face +
- addr.bits.level * 7);
-
- return entry % NUM_ENTRIES;
-}
-
-/**
- * Similar to lp_get_cached_tile() but for textures.
- * Tiles are read-only and indexed with more params.
- */
-const struct llvmpipe_cached_tex_tile *
-lp_find_cached_tex_tile(struct llvmpipe_tex_tile_cache *tc,
- union tex_tile_address addr )
-{
- struct pipe_screen *screen = tc->screen;
- struct llvmpipe_cached_tex_tile *tile;
-
- tile = tc->entries + tex_cache_pos( addr );
-
- if (addr.value != tile->addr.value) {
-
- /* cache miss. Most misses are because we've invaldiated the
- * texture cache previously -- most commonly on binding a new
- * texture. Currently we effectively flush the cache on texture
- * bind.
- */
-#if 0
- _debug_printf("miss at %u: x=%d y=%d z=%d face=%d level=%d\n"
- " tile %u: x=%d y=%d z=%d face=%d level=%d\n",
- pos, x/TEX_TILE_SIZE, y/TEX_TILE_SIZE, z, face, level,
- pos, tile->addr.bits.x, tile->addr.bits.y, tile->z, tile->face, tile->level);
-#endif
-
- /* check if we need to get a new transfer */
- if (!tc->tex_trans ||
- tc->tex_face != addr.bits.face ||
- tc->tex_level != addr.bits.level ||
- tc->tex_z != addr.bits.z) {
- /* get new transfer (view into texture) */
-
- if (tc->tex_trans) {
- if (tc->tex_trans_map) {
- tc->screen->transfer_unmap(tc->screen, tc->tex_trans);
- tc->tex_trans_map = NULL;
- }
-
- screen->tex_transfer_destroy(tc->tex_trans);
- tc->tex_trans = NULL;
- }
-
- tc->tex_trans =
- screen->get_tex_transfer(screen, tc->texture,
- addr.bits.face,
- addr.bits.level,
- addr.bits.z,
- PIPE_TRANSFER_READ, 0, 0,
- u_minify(tc->texture->width0, addr.bits.level),
- u_minify(tc->texture->height0, addr.bits.level));
-
- tc->tex_trans_map = screen->transfer_map(screen, tc->tex_trans);
-
- tc->tex_face = addr.bits.face;
- tc->tex_level = addr.bits.level;
- tc->tex_z = addr.bits.z;
- }
-
- {
- unsigned x = addr.bits.x * TEX_TILE_SIZE;
- unsigned y = addr.bits.y * TEX_TILE_SIZE;
- unsigned w = TEX_TILE_SIZE;
- unsigned h = TEX_TILE_SIZE;
-
- if (pipe_clip_tile(x, y, &w, &h, tc->tex_trans)) {
- assert(0);
- }
-
- util_format_read_4ub(tc->tex_trans->texture->format,
- (uint8_t *)tile->color, sizeof tile->color[0],
- tc->tex_trans_map, tc->tex_trans->stride,
- x, y, w, h);
- }
-
- tile->addr = addr;
- }
-
- tc->last_tile = tile;
- return tile;
-}
diff --git a/src/gallium/drivers/llvmpipe/lp_tex_cache.h b/src/gallium/drivers/llvmpipe/lp_tex_cache.h
deleted file mode 100644
index 05fded78e1..0000000000
--- a/src/gallium/drivers/llvmpipe/lp_tex_cache.h
+++ /dev/null
@@ -1,151 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
- * 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 TUNGSTEN GRAPHICS 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 LP_TEX_CACHE_H
-#define LP_TEX_CACHE_H
-
-
-#include "pipe/p_compiler.h"
-
-
-struct llvmpipe_context;
-struct llvmpipe_tex_tile_cache;
-
-
-/**
- * Cache tile size (width and height). This needs to be a power of two.
- */
-#define TEX_TILE_SIZE 64
-
-
-/* If we need to support > 4096, just expand this to be a 64 bit
- * union, or consider tiling in Z as well.
- */
-union tex_tile_address {
- struct {
- unsigned x:6; /* 4096 / TEX_TILE_SIZE */
- unsigned y:6; /* 4096 / TEX_TILE_SIZE */
- unsigned z:12; /* 4096 -- z not tiled */
- unsigned face:3;
- unsigned level:4;
- unsigned invalid:1;
- } bits;
- unsigned value;
-};
-
-
-struct llvmpipe_cached_tex_tile
-{
- union tex_tile_address addr;
- uint8_t color[TEX_TILE_SIZE][TEX_TILE_SIZE][4];
-};
-
-#define NUM_ENTRIES 50
-
-
-/** XXX move these */
-#define MAX_TEX_WIDTH 2048
-#define MAX_TEX_HEIGHT 2048
-
-
-struct llvmpipe_tex_tile_cache
-{
- struct pipe_screen *screen;
- struct pipe_surface *surface; /**< the surface we're caching */
- struct pipe_transfer *transfer;
- void *transfer_map;
-
- struct pipe_texture *texture; /**< if caching a texture */
- unsigned timestamp;
-
- struct llvmpipe_cached_tex_tile entries[NUM_ENTRIES];
-
- struct pipe_transfer *tex_trans;
- void *tex_trans_map;
- int tex_face, tex_level, tex_z;
-
- struct llvmpipe_cached_tex_tile *last_tile; /**< most recently retrieved tile */
-};
-
-
-extern struct llvmpipe_tex_tile_cache *
-lp_create_tex_tile_cache( struct pipe_screen *screen );
-
-extern void
-lp_destroy_tex_tile_cache(struct llvmpipe_tex_tile_cache *tc);
-
-extern void
-lp_tex_tile_cache_map_transfers(struct llvmpipe_tex_tile_cache *tc);
-
-extern void
-lp_tex_tile_cache_unmap_transfers(struct llvmpipe_tex_tile_cache *tc);
-
-extern void
-lp_tex_tile_cache_set_texture(struct llvmpipe_tex_tile_cache *tc,
- struct pipe_texture *texture);
-
-void
-lp_tex_tile_cache_validate_texture(struct llvmpipe_tex_tile_cache *tc);
-
-extern const struct llvmpipe_cached_tex_tile *
-lp_find_cached_tex_tile(struct llvmpipe_tex_tile_cache *tc,
- union tex_tile_address addr );
-
-static INLINE union tex_tile_address
-tex_tile_address( unsigned x,
- unsigned y,
- unsigned z,
- unsigned face,
- unsigned level )
-{
- union tex_tile_address addr;
-
- addr.value = 0;
- addr.bits.x = x / TEX_TILE_SIZE;
- addr.bits.y = y / TEX_TILE_SIZE;
- addr.bits.z = z;
- addr.bits.face = face;
- addr.bits.level = level;
-
- return addr;
-}
-
-/* Quickly retrieve tile if it matches last lookup.
- */
-static INLINE const struct llvmpipe_cached_tex_tile *
-lp_get_cached_tex_tile(struct llvmpipe_tex_tile_cache *tc,
- union tex_tile_address addr )
-{
- if (tc->last_tile->addr.value == addr.value)
- return tc->last_tile;
-
- return lp_find_cached_tex_tile( tc, addr );
-}
-
-
-#endif /* LP_TEX_CACHE_H */
-
diff --git a/src/gallium/drivers/llvmpipe/lp_tex_sample_llvm.c b/src/gallium/drivers/llvmpipe/lp_tex_sample_llvm.c
index d2a6ae21f5..d59d768139 100644
--- a/src/gallium/drivers/llvmpipe/lp_tex_sample_llvm.c
+++ b/src/gallium/drivers/llvmpipe/lp_tex_sample_llvm.c
@@ -47,7 +47,7 @@
#include "lp_bld_intr.h"
#include "lp_bld_sample.h"
#include "lp_bld_tgsi.h"
-#include "lp_state.h"
+#include "lp_jit.h"
#include "lp_tex_sample.h"
diff --git a/src/gallium/drivers/llvmpipe/lp_texture.c b/src/gallium/drivers/llvmpipe/lp_texture.c
index 2c135029ea..2462378152 100644
--- a/src/gallium/drivers/llvmpipe/lp_texture.c
+++ b/src/gallium/drivers/llvmpipe/lp_texture.c
@@ -42,7 +42,6 @@
#include "lp_context.h"
#include "lp_state.h"
#include "lp_texture.h"
-#include "lp_tex_cache.h"
#include "lp_screen.h"
#include "lp_winsys.h"
@@ -236,7 +235,7 @@ llvmpipe_get_tex_surface(struct pipe_screen *screen,
if (ps->usage & (PIPE_BUFFER_USAGE_CPU_WRITE |
PIPE_BUFFER_USAGE_GPU_WRITE)) {
- /* Mark the surface as dirty. The tile cache will look for this. */
+ /* Mark the surface as dirty. */
lpt->timestamp++;
llvmpipe_screen(screen)->timestamp++;
}
@@ -373,7 +372,6 @@ llvmpipe_transfer_map( struct pipe_screen *_screen,
if (transfer->texture && (transfer->usage & PIPE_TRANSFER_WRITE))
{
/* Do something to notify sharing contexts of a texture change.
- * In llvmpipe, that would mean flushing the texture cache.
*/
screen->timestamp++;
}
diff --git a/src/gallium/drivers/llvmpipe/lp_tile_cache.c b/src/gallium/drivers/llvmpipe/lp_tile_cache.c
deleted file mode 100644
index 7a1ecf5107..0000000000
--- a/src/gallium/drivers/llvmpipe/lp_tile_cache.c
+++ /dev/null
@@ -1,358 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
- * 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 TUNGSTEN GRAPHICS 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.
- *
- **************************************************************************/
-
-/**
- * Texture tile caching.
- *
- * Author:
- * Brian Paul
- */
-
-#include "pipe/p_inlines.h"
-#include "util/u_memory.h"
-#include "util/u_math.h"
-#include "util/u_tile.h"
-#include "util/u_rect.h"
-#include "lp_context.h"
-#include "lp_surface.h"
-#include "lp_texture.h"
-#include "lp_tile_soa.h"
-#include "lp_tile_cache.h"
-
-
-#define MAX_WIDTH 4096
-#define MAX_HEIGHT 4096
-
-
-enum llvmpipe_tile_status
-{
- LP_TILE_STATUS_UNDEFINED = 0,
- LP_TILE_STATUS_CLEAR = 1,
- LP_TILE_STATUS_DEFINED = 2
-};
-
-
-struct llvmpipe_cached_tile
-{
- enum llvmpipe_tile_status status;
-
- /** color in SOA format */
- uint8_t *color;
-};
-
-
-struct llvmpipe_tile_cache
-{
- struct pipe_screen *screen;
- struct pipe_surface *surface; /**< the surface we're caching */
- struct pipe_transfer *transfer;
- void *transfer_map;
-
- struct llvmpipe_cached_tile entries[MAX_WIDTH/TILE_SIZE][MAX_HEIGHT/TILE_SIZE];
-
- uint8_t clear_color[4]; /**< for color bufs */
- uint clear_val; /**< for z+stencil, or packed color clear value */
-
- struct llvmpipe_cached_tile *last_tile; /**< most recently retrieved tile */
-};
-
-
-struct llvmpipe_tile_cache *
-lp_create_tile_cache( struct pipe_screen *screen )
-{
- struct llvmpipe_tile_cache *tc;
- int maxLevels, maxTexSize;
-
- /* sanity checking: max sure MAX_WIDTH/HEIGHT >= largest texture image */
- maxLevels = screen->get_param(screen, PIPE_CAP_MAX_TEXTURE_2D_LEVELS);
- maxTexSize = 1 << (maxLevels - 1);
- assert(MAX_WIDTH >= maxTexSize);
-
- tc = CALLOC_STRUCT( llvmpipe_tile_cache );
- if(!tc)
- return NULL;
-
- tc->screen = screen;
-
- return tc;
-}
-
-
-void
-lp_destroy_tile_cache(struct llvmpipe_tile_cache *tc)
-{
- struct pipe_screen *screen;
- unsigned x, y;
-
- for (y = 0; y < MAX_HEIGHT; y += TILE_SIZE) {
- for (x = 0; x < MAX_WIDTH; x += TILE_SIZE) {
- struct llvmpipe_cached_tile *tile = &tc->entries[y/TILE_SIZE][x/TILE_SIZE];
-
- if(tile->color)
- align_free(tile->color);
- }
- }
-
- if (tc->transfer) {
- screen = tc->transfer->texture->screen;
- screen->tex_transfer_destroy(tc->transfer);
- }
-
- FREE( tc );
-}
-
-
-/**
- * Specify the surface to cache.
- */
-void
-lp_tile_cache_set_surface(struct llvmpipe_tile_cache *tc,
- struct pipe_surface *ps)
-{
- if (tc->transfer) {
- struct pipe_screen *screen = tc->transfer->texture->screen;
-
- if (ps == tc->surface)
- return;
-
- if (tc->transfer_map) {
- screen->transfer_unmap(screen, tc->transfer);
- tc->transfer_map = NULL;
- }
-
- screen->tex_transfer_destroy(tc->transfer);
- tc->transfer = NULL;
- }
-
- tc->surface = ps;
-
- if (ps) {
- struct pipe_screen *screen = ps->texture->screen;
- unsigned x, y;
-
- tc->transfer = screen->get_tex_transfer(screen, ps->texture, ps->face,
- ps->level, ps->zslice,
- PIPE_TRANSFER_READ_WRITE,
- 0, 0, ps->width, ps->height);
-
- for (y = 0; y < ps->height; y += TILE_SIZE) {
- for (x = 0; x < ps->width; x += TILE_SIZE) {
- struct llvmpipe_cached_tile *tile = &tc->entries[y/TILE_SIZE][x/TILE_SIZE];
-
- tile->status = LP_TILE_STATUS_UNDEFINED;
-
- if(!tile->color)
- tile->color = align_malloc( TILE_SIZE*TILE_SIZE*NUM_CHANNELS, 16 );
- }
- }
- }
-}
-
-
-/**
- * Return the transfer being cached.
- */
-struct pipe_surface *
-lp_tile_cache_get_surface(struct llvmpipe_tile_cache *tc)
-{
- return tc->surface;
-}
-
-
-void
-lp_tile_cache_map_transfers(struct llvmpipe_tile_cache *tc)
-{
- if (tc->transfer && !tc->transfer_map)
- tc->transfer_map = tc->screen->transfer_map(tc->screen, tc->transfer);
-}
-
-
-void
-lp_tile_cache_unmap_transfers(struct llvmpipe_tile_cache *tc)
-{
- if (tc->transfer_map) {
- tc->screen->transfer_unmap(tc->screen, tc->transfer);
- tc->transfer_map = NULL;
- }
-}
-
-
-/**
- * Set a tile to a solid color.
- */
-static void
-clear_tile(struct llvmpipe_cached_tile *tile,
- uint8_t clear_color[4])
-{
- if (clear_color[0] == clear_color[1] &&
- clear_color[1] == clear_color[2] &&
- clear_color[2] == clear_color[3]) {
- memset(tile->color, clear_color[0], TILE_SIZE * TILE_SIZE * 4);
- }
- else {
- uint x, y, chan;
- for (y = 0; y < TILE_SIZE; y++)
- for (x = 0; x < TILE_SIZE; x++)
- for (chan = 0; chan < 4; ++chan)
- TILE_PIXEL(tile->color, x, y, chan) = clear_color[chan];
- }
-}
-
-
-/**
- * Flush the tile cache: write all dirty tiles back to the transfer.
- * any tiles "flagged" as cleared will be "really" cleared.
- */
-void
-lp_flush_tile_cache(struct llvmpipe_tile_cache *tc)
-{
- struct pipe_transfer *pt = tc->transfer;
- unsigned x, y;
-
- if(!pt)
- return;
-
- assert(tc->transfer_map);
-
- /* push the tile to all positions marked as clear */
- for (y = 0; y < pt->height; y += TILE_SIZE) {
- for (x = 0; x < pt->width; x += TILE_SIZE) {
- struct llvmpipe_cached_tile *tile = &tc->entries[y/TILE_SIZE][x/TILE_SIZE];
-
- if(tile->status != LP_TILE_STATUS_UNDEFINED) {
- unsigned w = TILE_SIZE;
- unsigned h = TILE_SIZE;
-
- if (!pipe_clip_tile(x, y, &w, &h, pt)) {
- switch(tile->status) {
- case LP_TILE_STATUS_CLEAR:
- /* Actually clear the tiles which were flagged as being in a
- * clear state. */
- util_fill_rect(tc->transfer_map, pt->texture->format, pt->stride,
- x, y, w, h,
- tc->clear_val);
- break;
-
- case LP_TILE_STATUS_DEFINED:
- lp_tile_write_4ub(pt->texture->format,
- tile->color,
- tc->transfer_map, pt->stride,
- x, y, w, h);
- break;
-
- default:
- assert(0);
- break;
- }
- }
-
- tile->status = LP_TILE_STATUS_UNDEFINED;
- }
- }
- }
-}
-
-
-/**
- * Get a tile from the cache.
- * \param x, y position of tile, in pixels
- */
-void *
-lp_get_cached_tile(struct llvmpipe_tile_cache *tc,
- unsigned x, unsigned y )
-{
- struct llvmpipe_cached_tile *tile = &tc->entries[y/TILE_SIZE][x/TILE_SIZE];
- struct pipe_transfer *pt = tc->transfer;
-
- assert(tc->surface);
- assert(tc->transfer);
-
- if(!tc->transfer_map)
- lp_tile_cache_map_transfers(tc);
-
- assert(tc->transfer_map);
-
- switch(tile->status) {
- case LP_TILE_STATUS_CLEAR:
- /* don't get tile from framebuffer, just clear it */
- clear_tile(tile, tc->clear_color);
- tile->status = LP_TILE_STATUS_DEFINED;
- break;
-
- case LP_TILE_STATUS_UNDEFINED: {
- unsigned w = TILE_SIZE;
- unsigned h = TILE_SIZE;
-
- x &= ~(TILE_SIZE - 1);
- y &= ~(TILE_SIZE - 1);
-
- if (!pipe_clip_tile(x, y, &w, &h, tc->transfer))
- lp_tile_read_4ub(pt->texture->format,
- tile->color,
- tc->transfer_map, tc->transfer->stride,
- x, y, w, h);
-
- tile->status = LP_TILE_STATUS_DEFINED;
- break;
- }
-
- case LP_TILE_STATUS_DEFINED:
- /* nothing to do */
- break;
- }
-
- return tile->color;
-}
-
-
-/**
- * When a whole surface is being cleared to a value we can avoid
- * fetching tiles above.
- * Save the color and set a 'clearflag' for each tile of the screen.
- */
-void
-lp_tile_cache_clear(struct llvmpipe_tile_cache *tc, const float *rgba,
- uint clearValue)
-{
- struct pipe_transfer *pt = tc->transfer;
- const unsigned w = pt->width;
- const unsigned h = pt->height;
- unsigned x, y, chan;
-
- for(chan = 0; chan < 4; ++chan)
- tc->clear_color[chan] = float_to_ubyte(rgba[chan]);
-
- tc->clear_val = clearValue;
-
- /* push the tile to all positions marked as clear */
- for (y = 0; y < h; y += TILE_SIZE) {
- for (x = 0; x < w; x += TILE_SIZE) {
- struct llvmpipe_cached_tile *tile = &tc->entries[y/TILE_SIZE][x/TILE_SIZE];
- tile->status = LP_TILE_STATUS_CLEAR;
- }
- }
-}
diff --git a/src/gallium/drivers/llvmpipe/lp_tile_soa.h b/src/gallium/drivers/llvmpipe/lp_tile_soa.h
index 19d00b58d3..1b7be3cce0 100644
--- a/src/gallium/drivers/llvmpipe/lp_tile_soa.h
+++ b/src/gallium/drivers/llvmpipe/lp_tile_soa.h
@@ -43,23 +43,24 @@ struct pipe_transfer;
/**
* Cache tile size (width and height). This needs to be a power of two.
*/
-#define TILE_SIZE 64
+#define TILE_ORDER 6
+#define TILE_SIZE (1 << TILE_ORDER)
-#define TILE_VECTOR_HEIGHT 2
-#define TILE_VECTOR_WIDTH 8
+#define TILE_VECTOR_HEIGHT 4
+#define TILE_VECTOR_WIDTH 4
extern const unsigned char
tile_offset[TILE_VECTOR_HEIGHT][TILE_VECTOR_WIDTH];
-#define TILE_C_STRIDE (TILE_VECTOR_HEIGHT*TILE_VECTOR_WIDTH)
-#define TILE_X_STRIDE (NUM_CHANNELS*TILE_C_STRIDE)
-#define TILE_Y_STRIDE (TILE_VECTOR_HEIGHT*TILE_SIZE*NUM_CHANNELS)
+#define TILE_C_STRIDE (TILE_VECTOR_HEIGHT * TILE_VECTOR_WIDTH)
+#define TILE_X_STRIDE (NUM_CHANNELS * TILE_C_STRIDE)
+#define TILE_Y_STRIDE (TILE_VECTOR_HEIGHT * TILE_SIZE * NUM_CHANNELS)
#define TILE_PIXEL(_p, _x, _y, _c) \
- ((_p)[((_y)/TILE_VECTOR_HEIGHT)*TILE_Y_STRIDE + \
- ((_x)/TILE_VECTOR_WIDTH)*TILE_X_STRIDE + \
- (_c)*TILE_C_STRIDE + \
+ ((_p)[((_y) / TILE_VECTOR_HEIGHT) * TILE_Y_STRIDE + \
+ ((_x) / TILE_VECTOR_WIDTH) * TILE_X_STRIDE + \
+ (_c) * TILE_C_STRIDE + \
tile_offset[(_y) % TILE_VECTOR_HEIGHT][(_x) % TILE_VECTOR_WIDTH]])
diff --git a/src/gallium/drivers/llvmpipe/lp_tile_soa.py b/src/gallium/drivers/llvmpipe/lp_tile_soa.py
index 004c5c979e..a603b7f9f4 100644
--- a/src/gallium/drivers/llvmpipe/lp_tile_soa.py
+++ b/src/gallium/drivers/llvmpipe/lp_tile_soa.py
@@ -259,8 +259,10 @@ def main():
print
print 'const unsigned char'
print 'tile_offset[TILE_VECTOR_HEIGHT][TILE_VECTOR_WIDTH] = {'
- print ' { 0, 1, 4, 5, 8, 9, 12, 13},'
- print ' { 2, 3, 6, 7, 10, 11, 14, 15}'
+ print ' { 0, 1, 4, 5},'
+ print ' { 2, 3, 6, 7},'
+ print ' { 8, 9, 12, 13},'
+ print ' { 10, 11, 14, 15}'
print '};'
print
diff --git a/src/gallium/include/pipe/p_thread.h b/src/gallium/include/pipe/p_thread.h
index 25e4148232..8119c1f571 100644
--- a/src/gallium/include/pipe/p_thread.h
+++ b/src/gallium/include/pipe/p_thread.h
@@ -27,7 +27,8 @@
/**
* @file
*
- * Thread, mutex, condition var and thread-specific data functions.
+ * Thread, mutex, condition variable, barrier, semaphore and
+ * thread-specific data functions.
*/
@@ -46,6 +47,8 @@
#define PIPE_THREAD_HAVE_CONDVAR
+/* pipe_thread
+ */
typedef pthread_t pipe_thread;
#define PIPE_THREAD_ROUTINE( name, param ) \
@@ -69,8 +72,10 @@ static INLINE int pipe_thread_destroy( pipe_thread thread )
return pthread_detach( thread );
}
+
+/* pipe_mutex
+ */
typedef pthread_mutex_t pipe_mutex;
-typedef pthread_cond_t pipe_condvar;
#define pipe_static_mutex(mutex) \
static pipe_mutex mutex = PTHREAD_MUTEX_INITIALIZER
@@ -87,6 +92,11 @@ typedef pthread_cond_t pipe_condvar;
#define pipe_mutex_unlock(mutex) \
(void) pthread_mutex_unlock(&(mutex))
+
+/* pipe_condvar
+ */
+typedef pthread_cond_t pipe_condvar;
+
#define pipe_static_condvar(mutex) \
static pipe_condvar mutex = PTHREAD_COND_INITIALIZER
@@ -106,10 +116,32 @@ typedef pthread_cond_t pipe_condvar;
pthread_cond_broadcast(&(cond))
+/* pipe_barrier
+ */
+typedef pthread_barrier_t pipe_barrier;
+
+static INLINE void pipe_barrier_init(pipe_barrier *barrier, unsigned count)
+{
+ pthread_barrier_init(barrier, NULL, count);
+}
+
+static INLINE void pipe_barrier_destroy(pipe_barrier *barrier)
+{
+ pthread_barrier_destroy(barrier);
+}
+
+static INLINE void pipe_barrier_wait(pipe_barrier *barrier)
+{
+ pthread_barrier_wait(barrier);
+}
+
+
#elif defined(PIPE_SUBSYSTEM_WINDOWS_USER)
#include <windows.h>
+/* pipe_thread
+ */
typedef HANDLE pipe_thread;
#define PIPE_THREAD_ROUTINE( name, param ) \
@@ -135,6 +167,9 @@ static INLINE int pipe_thread_destroy( pipe_thread thread )
return -1;
}
+
+/* pipe_mutex
+ */
typedef CRITICAL_SECTION pipe_mutex;
#define pipe_static_mutex(mutex) \
@@ -152,15 +187,48 @@ typedef CRITICAL_SECTION pipe_mutex;
#define pipe_mutex_unlock(mutex) \
LeaveCriticalSection(&mutex)
-/* XXX: dummy definitions, make it compile */
+/* pipe_condvar (XXX FIX THIS)
+ */
typedef unsigned pipe_condvar;
-#define pipe_condvar_init(condvar) \
- (void) condvar
+#define pipe_condvar_init(cond) \
+ (void) cond
+
+#define pipe_condvar_destroy(cond) \
+ (void) cond
+
+#define pipe_condvar_wait(cond, mutex) \
+ (void) cond; (void) mutex
+
+#define pipe_condvar_signal(cond) \
+ (void) cond
+
+#define pipe_condvar_broadcast(cond) \
+ (void) cond
+
+
+/* pipe_barrier (XXX FIX THIS)
+ */
+typedef unsigned pipe_barrier;
+
+static INLINE void pipe_barrier_init(pipe_barrier *barrier, unsigned count)
+{
+ /* XXX we could implement barriers with a mutex and condition var */
+ assert(0);
+}
+
+static INLINE void pipe_barrier_destroy(pipe_barrier *barrier)
+{
+ assert(0);
+}
+
+static INLINE void pipe_barrier_wait(pipe_barrier *barrier)
+{
+ assert(0);
+}
+
-#define pipe_condvar_broadcast(condvar) \
- (void) condvar
#else
@@ -169,6 +237,7 @@ typedef unsigned pipe_condvar;
typedef unsigned pipe_thread;
typedef unsigned pipe_mutex;
typedef unsigned pipe_condvar;
+typedef unsigned pipe_barrier;
#define pipe_static_mutex(mutex) \
static pipe_mutex mutex = 0
@@ -204,9 +273,77 @@ typedef unsigned pipe_condvar;
(void) condvar
+static INLINE void pipe_barrier_init(pipe_barrier *barrier, unsigned count)
+{
+ /* XXX we could implement barriers with a mutex and condition var */
+ assert(0);
+}
+
+static INLINE void pipe_barrier_destroy(pipe_barrier *barrier)
+{
+ assert(0);
+}
+
+static INLINE void pipe_barrier_wait(pipe_barrier *barrier)
+{
+ assert(0);
+}
+
+
+
#endif /* PIPE_OS_? */
+/*
+ * Semaphores
+ */
+
+typedef struct
+{
+ pipe_mutex mutex;
+ pipe_condvar cond;
+ int counter;
+} pipe_semaphore;
+
+
+static INLINE void
+pipe_semaphore_init(pipe_semaphore *sema, int init_val)
+{
+ pipe_mutex_init(sema->mutex);
+ pipe_condvar_init(sema->cond);
+ sema->counter = init_val;
+}
+
+static INLINE void
+pipe_semaphore_destroy(pipe_semaphore *sema)
+{
+ pipe_mutex_destroy(sema->mutex);
+ pipe_condvar_destroy(sema->cond);
+}
+
+/** Signal/increment semaphore counter */
+static INLINE void
+pipe_semaphore_signal(pipe_semaphore *sema)
+{
+ pipe_mutex_lock(sema->mutex);
+ sema->counter++;
+ pipe_condvar_signal(sema->cond);
+ pipe_mutex_unlock(sema->mutex);
+}
+
+/** Wait for semaphore counter to be greater than zero */
+static INLINE void
+pipe_semaphore_wait(pipe_semaphore *sema)
+{
+ pipe_mutex_lock(sema->mutex);
+ while (sema->counter <= 0) {
+ pipe_condvar_wait(sema->cond, sema->mutex);
+ }
+ sema->counter--;
+ pipe_mutex_unlock(sema->mutex);
+}
+
+
/*
* Thread-specific data.