{
struct gallivm_state *gallivm = lp->gallivm;
LLVMContextRef lc = gallivm->context;
- LLVMTypeRef texture_type, sampler_type;
+ LLVMTypeRef viewport_type, texture_type, sampler_type;
+
+ /* struct lp_jit_viewport */
+ {
+ LLVMTypeRef elem_types[LP_JIT_VIEWPORT_NUM_FIELDS];
+
+ elem_types[LP_JIT_VIEWPORT_MIN_DEPTH] =
+ elem_types[LP_JIT_VIEWPORT_MAX_DEPTH] = LLVMFloatTypeInContext(lc);
+
+ viewport_type = LLVMStructTypeInContext(lc, elem_types,
+ Elements(elem_types), 0);
+
+#if HAVE_LLVM < 0x0300
+ LLVMAddTypeName(gallivm->module, "viewport", viewport_type);
+
+ LLVMInvalidateStructLayout(gallivm->target, viewport_type);
+#endif
+
+ LP_CHECK_MEMBER_OFFSET(struct lp_jit_viewport, min_depth,
+ gallivm->target, viewport_type,
+ LP_JIT_VIEWPORT_MIN_DEPTH);
+ LP_CHECK_MEMBER_OFFSET(struct lp_jit_viewport, max_depth,
+ gallivm->target, viewport_type,
+ LP_JIT_VIEWPORT_MAX_DEPTH);
+ LP_CHECK_STRUCT_SIZE(struct lp_jit_viewport,
+ gallivm->target, viewport_type);
+ }
/* struct lp_jit_texture */
{
gallivm->target, texture_type);
}
- {
/* struct lp_jit_sampler */
+ {
LLVMTypeRef elem_types[LP_JIT_SAMPLER_NUM_FIELDS];
elem_types[LP_JIT_SAMPLER_MIN_LOD] =
elem_types[LP_JIT_SAMPLER_MAX_LOD] =
sampler_type = LLVMStructTypeInContext(lc, elem_types,
Elements(elem_types), 0);
#if HAVE_LLVM < 0x0300
- LLVMAddTypeName(gallivm->module, "texture", texture_type);
+ LLVMAddTypeName(gallivm->module, "sampler", sampler_type);
- LLVMInvalidateStructLayout(gallivm->target, texture_type);
+ LLVMInvalidateStructLayout(gallivm->target, sampler_type);
#endif
LP_CHECK_MEMBER_OFFSET(struct lp_jit_sampler, min_lod,
- gallivm->target, texture_type,
+ gallivm->target, sampler_type,
LP_JIT_SAMPLER_MIN_LOD);
LP_CHECK_MEMBER_OFFSET(struct lp_jit_sampler, max_lod,
- gallivm->target, texture_type,
+ gallivm->target, sampler_type,
LP_JIT_SAMPLER_MAX_LOD);
LP_CHECK_MEMBER_OFFSET(struct lp_jit_sampler, lod_bias,
- gallivm->target, texture_type,
+ gallivm->target, sampler_type,
LP_JIT_SAMPLER_LOD_BIAS);
LP_CHECK_MEMBER_OFFSET(struct lp_jit_sampler, border_color,
- gallivm->target, texture_type,
+ gallivm->target, sampler_type,
LP_JIT_SAMPLER_BORDER_COLOR);
LP_CHECK_STRUCT_SIZE(struct lp_jit_sampler,
gallivm->target, sampler_type);
elem_types[LP_JIT_CTX_STENCIL_REF_BACK] = LLVMInt32TypeInContext(lc);
elem_types[LP_JIT_CTX_U8_BLEND_COLOR] = LLVMPointerType(LLVMInt8TypeInContext(lc), 0);
elem_types[LP_JIT_CTX_F_BLEND_COLOR] = LLVMPointerType(LLVMFloatTypeInContext(lc), 0);
+ elem_types[LP_JIT_CTX_VIEWPORTS] = LLVMPointerType(viewport_type, 0);
elem_types[LP_JIT_CTX_TEXTURES] = LLVMArrayType(texture_type,
PIPE_MAX_SHADER_SAMPLER_VIEWS);
elem_types[LP_JIT_CTX_SAMPLERS] = LLVMArrayType(sampler_type,
LP_CHECK_MEMBER_OFFSET(struct lp_jit_context, f_blend_color,
gallivm->target, context_type,
LP_JIT_CTX_F_BLEND_COLOR);
+ LP_CHECK_MEMBER_OFFSET(struct lp_jit_context, viewports,
+ gallivm->target, context_type,
+ LP_JIT_CTX_VIEWPORTS);
LP_CHECK_MEMBER_OFFSET(struct lp_jit_context, textures,
gallivm->target, context_type,
LP_JIT_CTX_TEXTURES);
LLVMTypeRef thread_data_type;
elem_types[LP_JIT_THREAD_DATA_COUNTER] = LLVMInt64TypeInContext(lc);
+ elem_types[LP_JIT_THREAD_DATA_RASTER_STATE_VIEWPORT_INDEX] =
+ LLVMInt32TypeInContext(lc);
thread_data_type = LLVMStructTypeInContext(lc, elem_types,
Elements(elem_types), 0);
};
+struct lp_jit_viewport
+{
+ float min_depth;
+ float max_depth;
+};
+
+
enum {
LP_JIT_TEXTURE_WIDTH = 0,
LP_JIT_TEXTURE_HEIGHT,
};
+enum {
+ LP_JIT_VIEWPORT_MIN_DEPTH,
+ LP_JIT_VIEWPORT_MAX_DEPTH,
+ LP_JIT_VIEWPORT_NUM_FIELDS /* number of fields above */
+};
+
+
/**
* This structure is passed directly to the generated fragment shader.
*
uint8_t *u8_blend_color;
float *f_blend_color;
+ struct lp_jit_viewport *viewports;
+
struct lp_jit_texture textures[PIPE_MAX_SHADER_SAMPLER_VIEWS];
struct lp_jit_sampler samplers[PIPE_MAX_SAMPLERS];
};
LP_JIT_CTX_STENCIL_REF_BACK,
LP_JIT_CTX_U8_BLEND_COLOR,
LP_JIT_CTX_F_BLEND_COLOR,
+ LP_JIT_CTX_VIEWPORTS,
LP_JIT_CTX_TEXTURES,
LP_JIT_CTX_SAMPLERS,
LP_JIT_CTX_COUNT
#define lp_jit_context_f_blend_color(_gallivm, _ptr) \
lp_build_struct_get(_gallivm, _ptr, LP_JIT_CTX_F_BLEND_COLOR, "f_blend_color")
+#define lp_jit_context_viewports(_gallivm, _ptr) \
+ lp_build_struct_get(_gallivm, _ptr, LP_JIT_CTX_VIEWPORTS, "viewports")
+
#define lp_jit_context_textures(_gallivm, _ptr) \
lp_build_struct_get_ptr(_gallivm, _ptr, LP_JIT_CTX_TEXTURES, "textures")
struct lp_jit_thread_data
{
uint64_t vis_counter;
+
+ /*
+ * Non-interpolated rasterizer state passed through to the fragment shader.
+ */
+ struct {
+ uint32_t viewport_index;
+ } raster_state;
};
enum {
LP_JIT_THREAD_DATA_COUNTER = 0,
+ LP_JIT_THREAD_DATA_RASTER_STATE_VIEWPORT_INDEX,
LP_JIT_THREAD_DATA_COUNT
};
#define lp_jit_thread_data_counter(_gallivm, _ptr) \
lp_build_struct_get_ptr(_gallivm, _ptr, LP_JIT_THREAD_DATA_COUNTER, "counter")
-
+#define lp_jit_thread_data_raster_state_viewport_index(_gallivm, _ptr) \
+ lp_build_struct_get(_gallivm, _ptr, \
+ LP_JIT_THREAD_DATA_RASTER_STATE_VIEWPORT_INDEX, \
+ "raster_state.viewport_index")
+
/**
* typedef for fragment shader function
*
depth_stride = scene->zsbuf.stride;
}
+ /* Propagate non-interpolated raster state. */
+ task->thread_data.raster_state.viewport_index = inputs->viewport_index;
+
/* run shader on 4x4 block */
BEGIN_JIT_CALL(state, task);
variant->jit_function[RAST_WHOLE]( &state->jit_context,
/* always count this not worth bothering? */
task->ps_invocations += 1 * variant->ps_inv_multiplier;
+ /* Propagate non-interpolated raster state. */
+ task->thread_data.raster_state.viewport_index = inputs->viewport_index;
+
/* run shader on 4x4 block */
BEGIN_JIT_CALL(state, task);
variant->jit_function[RAST_EDGE_TEST](&state->jit_context,
unsigned pad0:29; /* wasted space */
unsigned stride; /* how much to advance data between a0, dadx, dady */
unsigned layer; /* the layer to render to (from gs, already clamped) */
- unsigned pad2; /* wasted space */
+ unsigned viewport_index; /* the active viewport index (from gs, already clamped) */
/* followed by a0, dadx, dady and planes[] */
};
/** "my" index */
unsigned thread_index;
- /* occlude counter for visible pixels */
+ /** Non-interpolated passthru state and occlude counter for visible pixels */
struct lp_jit_thread_data thread_data;
uint64_t ps_invocations;
uint8_t ps_inv_multiplier;
/* always count this not worth bothering? */
task->ps_invocations += 1 * variant->ps_inv_multiplier;
+ /* Propagate non-interpolated raster state. */
+ task->thread_data.raster_state.viewport_index = inputs->viewport_index;
+
/* run shader on 4x4 block */
BEGIN_JIT_CALL(state, task);
variant->jit_function[RAST_WHOLE]( &state->jit_context,
}
+/**
+ * Called during state validation when LP_NEW_VIEWPORT is set.
+ */
+void
+lp_setup_set_viewports(struct lp_setup_context *setup,
+ unsigned num_viewports,
+ const struct pipe_viewport_state *viewports)
+{
+ unsigned i;
+
+ LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__);
+
+ assert(num_viewports <= PIPE_MAX_VIEWPORTS);
+ assert(viewports);
+
+ /*
+ * For use in lp_state_fs.c, propagate the viewport values for all viewports.
+ */
+ for (i = 0; i < num_viewports; i++) {
+ float min_depth;
+ float max_depth;
+
+ min_depth = viewports[i].translate[2];
+ max_depth = viewports[i].translate[2] + viewports[i].scale[2];
+
+ if (setup->viewports[i].min_depth != min_depth ||
+ setup->viewports[i].max_depth != max_depth) {
+ setup->viewports[i].min_depth = min_depth;
+ setup->viewports[i].max_depth = max_depth;
+ setup->dirty |= LP_SETUP_NEW_VIEWPORTS;
+ }
+ }
+}
+
+
/**
* Called during state validation when LP_NEW_SAMPLER_VIEW is set.
*/
/**
* Called by vbuf code when we're about to draw something.
+ *
+ * This function stores all dirty state in the current scene's display list
+ * memory, via lp_scene_alloc(). We can not pass pointers of mutable state to
+ * the JIT functions, as the JIT functions will be called later on, most likely
+ * on a different thread.
+ *
+ * When processing dirty state it is imperative that we don't refer to any
+ * pointers previously allocated with lp_scene_alloc() in this function (or any
+ * function) as they may belong to a scene freed since then.
*/
static boolean
try_update_scene_state( struct lp_setup_context *setup )
assert(scene);
+ if (setup->dirty & LP_SETUP_NEW_VIEWPORTS) {
+ /*
+ * Record new depth range state for changes due to viewport updates.
+ *
+ * TODO: Collapse the existing viewport and depth range information
+ * into one structure, for access by JIT.
+ */
+ struct lp_jit_viewport *stored;
+
+ stored = (struct lp_jit_viewport *)
+ lp_scene_alloc(scene, sizeof setup->viewports);
+
+ if (!stored) {
+ assert(!new_scene);
+ return FALSE;
+ }
+
+ memcpy(stored, setup->viewports, sizeof setup->viewports);
+
+ setup->fs.current.jit_context.viewports = stored;
+ setup->dirty |= LP_SETUP_NEW_FS;
+ }
+
if(setup->dirty & LP_SETUP_NEW_BLEND_COLOR) {
uint8_t *stored;
float* fstored;
lp_setup_set_scissors( struct lp_setup_context *setup,
const struct pipe_scissor_state *scissors );
+void
+lp_setup_set_viewports(struct lp_setup_context *setup,
+ unsigned num_viewports,
+ const struct pipe_viewport_state *viewports);
+
void
lp_setup_set_fragment_sampler_views(struct lp_setup_context *setup,
unsigned num,
struct llvmpipe_query *pq);
static INLINE unsigned
-lp_clamp_scissor_idx(int idx)
+lp_clamp_viewport_idx(int idx)
{
return (PIPE_MAX_VIEWPORTS > idx && idx >= 0) ? idx : 0;
}
#define LP_SETUP_NEW_CONSTANTS 0x02
#define LP_SETUP_NEW_BLEND_COLOR 0x04
#define LP_SETUP_NEW_SCISSOR 0x08
+#define LP_SETUP_NEW_VIEWPORTS 0x10
struct lp_setup_variant;
struct u_rect framebuffer;
struct u_rect scissors[PIPE_MAX_VIEWPORTS];
struct u_rect draw_regions[PIPE_MAX_VIEWPORTS]; /* intersection of fb & scissor */
+ struct lp_jit_viewport viewports[PIPE_MAX_VIEWPORTS];
struct {
unsigned flags;
int y[4];
int i;
int nr_planes = 4;
- unsigned scissor_index = 0;
+ unsigned viewport_index = 0;
unsigned layer = 0;
/* linewidth should be interpreted as integer */
nr_planes = 8;
if (setup->viewport_index_slot > 0) {
unsigned *udata = (unsigned*)v1[setup->viewport_index_slot];
- scissor_index = lp_clamp_scissor_idx(*udata);
+ viewport_index = lp_clamp_viewport_idx(*udata);
}
}
else {
return TRUE;
}
- if (!u_rect_test_intersection(&setup->draw_regions[scissor_index], &bbox)) {
+ if (!u_rect_test_intersection(&setup->draw_regions[viewport_index], &bbox)) {
if (0) debug_printf("offscreen\n");
LP_COUNT(nr_culled_tris);
return TRUE;
line->inputs.disable = FALSE;
line->inputs.opaque = FALSE;
line->inputs.layer = layer;
+ line->inputs.viewport_index = viewport_index;
for (i = 0; i < 4; i++) {
*/
if (nr_planes == 8) {
const struct u_rect *scissor =
- &setup->scissors[scissor_index];
+ &setup->scissors[viewport_index];
plane[4].dcdx = -1;
plane[4].dcdy = 0;
plane[7].eo = 0;
}
- return lp_setup_bin_triangle(setup, line, &bbox, nr_planes, scissor_index);
+ return lp_setup_bin_triangle(setup, line, &bbox, nr_planes, viewport_index);
}
struct u_rect bbox;
unsigned nr_planes = 4;
struct point_info info;
- unsigned scissor_index = 0;
+ unsigned viewport_index = 0;
unsigned layer = 0;
if (setup->viewport_index_slot > 0) {
unsigned *udata = (unsigned*)v0[setup->viewport_index_slot];
- scissor_index = lp_clamp_scissor_idx(*udata);
+ viewport_index = lp_clamp_viewport_idx(*udata);
}
if (setup->layer_slot > 0) {
layer = *(unsigned*)v0[setup->layer_slot];
bbox.y1--;
}
- if (!u_rect_test_intersection(&setup->draw_regions[scissor_index], &bbox)) {
+ if (!u_rect_test_intersection(&setup->draw_regions[viewport_index], &bbox)) {
if (0) debug_printf("offscreen\n");
LP_COUNT(nr_culled_tris);
return TRUE;
}
- u_rect_find_intersection(&setup->draw_regions[scissor_index], &bbox);
+ u_rect_find_intersection(&setup->draw_regions[viewport_index], &bbox);
point = lp_setup_alloc_triangle(scene,
key->num_inputs,
point->inputs.disable = FALSE;
point->inputs.opaque = FALSE;
point->inputs.layer = layer;
+ point->inputs.viewport_index = viewport_index;
{
struct lp_rast_plane *plane = GET_PLANES(point);
plane[3].eo = 0;
}
- return lp_setup_bin_triangle(setup, point, &bbox, nr_planes, scissor_index);
+ return lp_setup_bin_triangle(setup, point, &bbox, nr_planes, viewport_index);
}
struct u_rect bbox;
unsigned tri_bytes;
int nr_planes = 3;
- unsigned scissor_index = 0;
+ unsigned viewport_index = 0;
unsigned layer = 0;
/* Area should always be positive here */
nr_planes = 7;
if (setup->viewport_index_slot > 0) {
unsigned *udata = (unsigned*)v0[setup->viewport_index_slot];
- scissor_index = lp_clamp_scissor_idx(*udata);
+ viewport_index = lp_clamp_viewport_idx(*udata);
}
}
else {
return TRUE;
}
- if (!u_rect_test_intersection(&setup->draw_regions[scissor_index], &bbox)) {
+ if (!u_rect_test_intersection(&setup->draw_regions[viewport_index], &bbox)) {
if (0) debug_printf("offscreen\n");
LP_COUNT(nr_culled_tris);
return TRUE;
tri->inputs.disable = FALSE;
tri->inputs.opaque = setup->fs.current.variant->opaque;
tri->inputs.layer = layer;
+ tri->inputs.viewport_index = viewport_index;
if (0)
lp_dump_setup_coef(&setup->setup.variant->key,
* these planes elsewhere.
*/
if (nr_planes == 7) {
- const struct u_rect *scissor = &setup->scissors[scissor_index];
+ const struct u_rect *scissor = &setup->scissors[viewport_index];
plane[3].dcdx = -1;
plane[3].dcdy = 0;
plane[6].eo = 0;
}
- return lp_setup_bin_triangle(setup, tri, &bbox, nr_planes, scissor_index);
+ return lp_setup_bin_triangle(setup, tri, &bbox, nr_planes, viewport_index);
}
/*
struct lp_rast_triangle *tri,
const struct u_rect *bbox,
int nr_planes,
- unsigned scissor_index )
+ unsigned viewport_index )
{
struct lp_scene *scene = setup->scene;
struct u_rect trimmed_box = *bbox;
* the rasterizer to also respect scissor, etc, just for the rare
* cases where a small triangle extends beyond the scissor.
*/
- u_rect_find_intersection(&setup->draw_regions[scissor_index],
+ u_rect_find_intersection(&setup->draw_regions[viewport_index],
&trimmed_box);
/* Determine which tile(s) intersect the triangle's bounding box
llvmpipe->num_samplers[PIPE_SHADER_FRAGMENT],
llvmpipe->samplers[PIPE_SHADER_FRAGMENT]);
+ if (llvmpipe->dirty & LP_NEW_VIEWPORT) {
+ /*
+ * Update setup and fragment's view of the active viewport state.
+ *
+ * XXX TODO: It is possible to only loop over the active viewports
+ * instead of all viewports (PIPE_MAX_VIEWPORTS).
+ */
+ lp_setup_set_viewports(llvmpipe->setup,
+ PIPE_MAX_VIEWPORTS,
+ llvmpipe->viewports);
+ }
+
llvmpipe->dirty = 0;
}
}
+/**
+ * Fetch the specified lp_jit_viewport structure for a given viewport_index.
+ */
+static LLVMValueRef
+lp_llvm_viewport(LLVMValueRef context_ptr,
+ struct gallivm_state *gallivm,
+ LLVMValueRef viewport_index)
+{
+ LLVMBuilderRef builder = gallivm->builder;
+ LLVMValueRef ptr;
+ LLVMValueRef res;
+ struct lp_type viewport_type =
+ lp_type_float_vec(32, 32 * LP_JIT_VIEWPORT_NUM_FIELDS);
+
+ ptr = lp_jit_context_viewports(gallivm, context_ptr);
+ ptr = LLVMBuildPointerCast(builder, ptr,
+ LLVMPointerType(lp_build_vec_type(gallivm, viewport_type), 0), "");
+
+ res = lp_build_pointer_get(builder, ptr, viewport_index);
+
+ return res;
+}
+
+
/**
* Generate the fragment shader, depth/stencil test, and alpha tests.
*/
0);
if (pos0 != -1 && outputs[pos0][2]) {
+ LLVMValueRef viewport, min_depth, max_depth;
+ LLVMValueRef viewport_index;
+ struct lp_build_context f32_bld;
+
+ assert(type.floating);
+ lp_build_context_init(&f32_bld, gallivm, type);
+
+ /*
+ * Assumes clamping of the viewport index will occur in setup/gs. Value
+ * is passed through the rasterization stage via lp_rast_shader_inputs.
+ *
+ * See: draw_clamp_viewport_idx and lp_clamp_viewport_idx for clamping
+ * semantics.
+ */
+ viewport_index = lp_jit_thread_data_raster_state_viewport_index(gallivm,
+ thread_data_ptr);
+
+ /*
+ * Load the min and max depth from the lp_jit_context.viewports
+ * array of lp_jit_viewport structures.
+ */
+ viewport = lp_llvm_viewport(context_ptr, gallivm, viewport_index);
+
+ /* viewports[viewport_index].min_depth */
+ min_depth = LLVMBuildExtractElement(builder, viewport,
+ lp_build_const_int32(gallivm, LP_JIT_VIEWPORT_MIN_DEPTH),
+ "");
+ min_depth = lp_build_broadcast_scalar(&f32_bld, min_depth);
+
+ /* viewports[viewport_index].max_depth */
+ max_depth = LLVMBuildExtractElement(builder, viewport,
+ lp_build_const_int32(gallivm, LP_JIT_VIEWPORT_MAX_DEPTH),
+ "");
+ max_depth = lp_build_broadcast_scalar(&f32_bld, max_depth);
+
z = LLVMBuildLoad(builder, outputs[pos0][2], "output.z");
+
+ /*
+ * Clamp to the min and max depth values for the given viewport.
+ */
+ z = lp_build_clamp(&f32_bld, z, min_depth, max_depth);
}
lp_build_depth_stencil_load_swizzled(gallivm, type,