llvmpipe: Add a linear rasterizer optimized for 2D rendering.
This change adds: - an alternative rasterizer, which rasterizes bins in a left->right & top->bottom linear fashion; - triangle -> rectangle detection; - 1:1 blit detection; - a special TGSI -> LLVM IR code generation that uses 8-bit SSE integers in AoS fashion (as opposed to 32bits floats.) Altogether these changes yield a 2x to 3x performance improvement for 2D workloads. It was designed to render Windows 7 Aero and other Windows built-in 3D applications (like Windows Media Player, Internet Explorer 11, UWP applications) with minimum CPU utilization, but it should be generally applicable to other 2D-on-3D applications, like desktop compositors, HTML browsers, 3D based UI toolkits, etc. This was mostly the brainchild of Keith Whitwell back in 2010. I wrote TGSI -> AoS translation. And many others added bug-fixes and enhancements over the years: Roland Scheidegger, Brian Paul, and James Benton. Known issues: - piglit spec@!opengl 1.1@quad-invariance will warn that "left and right half should match" due to rounding error difference - These optimized paths to kick in is that depth-buffer must not be used, so some applications which want to benefit from these improvements might need to be modified to ensure they use painter's algorithm instead of depth-buffers. Reviewed-by: Roland Scheidegger <sroland@vmware.com> Reviewed-by: Brian Paul <brianp@vmware.com> Acked-by: Keith Whitwell <keithw@vmware.com> v2: Incorporate Dave Airlie feedback: cleanup LP_DEBUG_xx; shrink 3+ empty lines. v3: silence unused var warning, adapt to new upstream code (point setup) Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/11969>
This commit is contained in:
committed by
Roland Scheidegger
parent
4dc81cc631
commit
5a1d3bcf26
@@ -454,7 +454,7 @@ lp_build_sample_image_nearest(struct lp_build_sample_context *bld,
|
||||
LLVMValueRef s_float, t_float = NULL, r_float = NULL;
|
||||
LLVMValueRef x_stride;
|
||||
LLVMValueRef x_offset, offset;
|
||||
LLVMValueRef x_subcoord, y_subcoord, z_subcoord;
|
||||
LLVMValueRef x_subcoord, y_subcoord = NULL, z_subcoord;
|
||||
|
||||
lp_build_context_init(&i32, bld->gallivm, lp_type_int_vec(32, bld->vector_width));
|
||||
|
||||
@@ -778,7 +778,7 @@ lp_build_sample_image_linear(struct lp_build_sample_context *bld,
|
||||
LLVMValueRef y_offset0, y_offset1;
|
||||
LLVMValueRef z_offset0, z_offset1;
|
||||
LLVMValueRef offset[2][2][2]; /* [z][y][x] */
|
||||
LLVMValueRef x_subcoord[2], y_subcoord[2], z_subcoord[2];
|
||||
LLVMValueRef x_subcoord[2], y_subcoord[2] = {NULL, NULL}, z_subcoord[2];
|
||||
unsigned x, y, z;
|
||||
|
||||
lp_build_context_init(&i32, bld->gallivm, lp_type_int_vec(32, bld->vector_width));
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright 2008 VMware, Inc.
|
||||
* Copyright 2008-2021 VMware, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
@@ -38,6 +38,8 @@
|
||||
#define U_SSE_H_
|
||||
|
||||
#include "pipe/p_config.h"
|
||||
#include "pipe/p_compiler.h"
|
||||
#include "util/u_debug.h"
|
||||
|
||||
#if defined(PIPE_ARCH_SSE)
|
||||
|
||||
@@ -296,6 +298,408 @@ transpose2_64_2_32(const __m128i * restrict a01,
|
||||
#define SCALAR_EPI32(m, i) _mm_shuffle_epi32((m), _MM_SHUFFLE(i,i,i,i))
|
||||
|
||||
|
||||
/*
|
||||
* Implements (1-w)*a + w*b = a - wa + wb = w(b-a) + a
|
||||
* ((b-a)*w >> 8) + a
|
||||
* The math behind negative sub results (logic shift/mask) is tricky.
|
||||
*
|
||||
* w -- weight values
|
||||
* a -- src0 values
|
||||
* b -- src1 values
|
||||
*/
|
||||
static ALWAYS_INLINE __m128i
|
||||
util_sse2_lerp_epi16(__m128i w, __m128i a, __m128i b)
|
||||
{
|
||||
__m128i res;
|
||||
|
||||
res = _mm_sub_epi16(b, a);
|
||||
res = _mm_mullo_epi16(res, w);
|
||||
res = _mm_srli_epi16(res, 8);
|
||||
/* use add_epi8 instead of add_epi16 so no need to mask off upper bits */
|
||||
res = _mm_add_epi8(res, a);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/* Apply premultiplied-alpha blending on two pixels simultaneously.
|
||||
* All parameters are packed as 8.8 fixed point values in __m128i SSE
|
||||
* registers, with the upper 8 bits all zero.
|
||||
*
|
||||
* a -- src alpha values
|
||||
* d -- dst color values
|
||||
* s -- src color values
|
||||
*/
|
||||
static inline __m128i
|
||||
util_sse2_premul_blend_epi16( __m128i a, __m128i d, __m128i s)
|
||||
{
|
||||
__m128i da, d_sub_da, tmp;
|
||||
tmp = _mm_mullo_epi16(d, a);
|
||||
da = _mm_srli_epi16(tmp, 8);
|
||||
d_sub_da = _mm_sub_epi16(d, da);
|
||||
|
||||
return _mm_add_epi16(s, d_sub_da);
|
||||
}
|
||||
|
||||
|
||||
/* Apply premultiplied-alpha blending on four pixels in packed BGRA
|
||||
* format (one/inv_src_alpha blend mode).
|
||||
*
|
||||
* src -- four pixels (bgra8 format)
|
||||
* dst -- four destination pixels (bgra8)
|
||||
* return -- blended pixels (bgra8)
|
||||
*/
|
||||
static ALWAYS_INLINE __m128i
|
||||
util_sse2_blend_premul_4(const __m128i src,
|
||||
const __m128i dst)
|
||||
{
|
||||
|
||||
__m128i al, ah, dl, dh, sl, sh, rl, rh;
|
||||
__m128i zero = _mm_setzero_si128();
|
||||
|
||||
/* Blend first two pixels:
|
||||
*/
|
||||
sl = _mm_unpacklo_epi8(src, zero);
|
||||
dl = _mm_unpacklo_epi8(dst, zero);
|
||||
|
||||
al = _mm_shufflehi_epi16(sl, 0xff);
|
||||
al = _mm_shufflelo_epi16(al, 0xff);
|
||||
|
||||
rl = util_sse2_premul_blend_epi16(al, dl, sl);
|
||||
|
||||
/* Blend second two pixels:
|
||||
*/
|
||||
sh = _mm_unpackhi_epi8(src, zero);
|
||||
dh = _mm_unpackhi_epi8(dst, zero);
|
||||
|
||||
ah = _mm_shufflehi_epi16(sh, 0xff);
|
||||
ah = _mm_shufflelo_epi16(ah, 0xff);
|
||||
|
||||
rh = util_sse2_premul_blend_epi16(ah, dh, sh);
|
||||
|
||||
/* Pack the results down to four bgra8 pixels:
|
||||
*/
|
||||
return _mm_packus_epi16(rl, rh);
|
||||
}
|
||||
|
||||
|
||||
/* Apply src-alpha blending on four pixels in packed BGRA
|
||||
* format (srcalpha/inv_src_alpha blend mode).
|
||||
*
|
||||
* src -- four pixels (bgra8 format)
|
||||
* dst -- four destination pixels (bgra8)
|
||||
* return -- blended pixels (bgra8)
|
||||
*/
|
||||
static ALWAYS_INLINE __m128i
|
||||
util_sse2_blend_srcalpha_4(const __m128i src,
|
||||
const __m128i dst)
|
||||
{
|
||||
|
||||
__m128i al, ah, dl, dh, sl, sh, rl, rh;
|
||||
__m128i zero = _mm_setzero_si128();
|
||||
|
||||
/* Blend first two pixels:
|
||||
*/
|
||||
sl = _mm_unpacklo_epi8(src, zero);
|
||||
dl = _mm_unpacklo_epi8(dst, zero);
|
||||
|
||||
al = _mm_shufflehi_epi16(sl, 0xff);
|
||||
al = _mm_shufflelo_epi16(al, 0xff);
|
||||
|
||||
rl = util_sse2_lerp_epi16(al, dl, sl);
|
||||
|
||||
/* Blend second two pixels:
|
||||
*/
|
||||
sh = _mm_unpackhi_epi8(src, zero);
|
||||
dh = _mm_unpackhi_epi8(dst, zero);
|
||||
|
||||
ah = _mm_shufflehi_epi16(sh, 0xff);
|
||||
ah = _mm_shufflelo_epi16(ah, 0xff);
|
||||
|
||||
rh = util_sse2_lerp_epi16(ah, dh, sh);
|
||||
|
||||
/* Pack the results down to four bgra8 pixels:
|
||||
*/
|
||||
return _mm_packus_epi16(rl, rh);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* premultiplies src with constant alpha then
|
||||
* does one/inv_src_alpha blend.
|
||||
*
|
||||
* src 16xi8 (normalized)
|
||||
* dst 16xi8 (normalized)
|
||||
* cst_alpha (constant alpha (u8 value))
|
||||
*/
|
||||
static ALWAYS_INLINE __m128i
|
||||
util_sse2_blend_premul_src_4(const __m128i src,
|
||||
const __m128i dst,
|
||||
const unsigned cst_alpha)
|
||||
{
|
||||
|
||||
__m128i srca, d, s, rl, rh;
|
||||
__m128i zero = _mm_setzero_si128();
|
||||
__m128i cst_alpha_vec = _mm_set1_epi16(cst_alpha);
|
||||
|
||||
/* Blend first two pixels:
|
||||
*/
|
||||
s = _mm_unpacklo_epi8(src, zero);
|
||||
s = _mm_mullo_epi16(s, cst_alpha_vec);
|
||||
/* the shift will cause some precision loss */
|
||||
s = _mm_srli_epi16(s, 8);
|
||||
|
||||
srca = _mm_shufflehi_epi16(s, 0xff);
|
||||
srca = _mm_shufflelo_epi16(srca, 0xff);
|
||||
|
||||
d = _mm_unpacklo_epi8(dst, zero);
|
||||
rl = util_sse2_premul_blend_epi16(srca, d, s);
|
||||
|
||||
/* Blend second two pixels:
|
||||
*/
|
||||
s = _mm_unpackhi_epi8(src, zero);
|
||||
s = _mm_mullo_epi16(s, cst_alpha_vec);
|
||||
/* the shift will cause some precision loss */
|
||||
s = _mm_srli_epi16(s, 8);
|
||||
|
||||
srca = _mm_shufflehi_epi16(s, 0xff);
|
||||
srca = _mm_shufflelo_epi16(srca, 0xff);
|
||||
|
||||
d = _mm_unpackhi_epi8(dst, zero);
|
||||
rh = util_sse2_premul_blend_epi16(srca, d, s);
|
||||
|
||||
/* Pack the results down to four bgra8 pixels:
|
||||
*/
|
||||
return _mm_packus_epi16(rl, rh);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Linear interpolation with SSE2.
|
||||
*
|
||||
* dst, src0, src1 are 16 x i8 vectors, with [0..255] normalized values.
|
||||
*
|
||||
* weight_lo and weight_hi should be a 8 x i16 vectors, in 8.8 fixed point
|
||||
* format, for the low and high components.
|
||||
* We'd want to pass these as values but MSVC limitation forces us to pass these
|
||||
* as pointers since it will complain if more than 3 __m128 are passed by value.
|
||||
*/
|
||||
static ALWAYS_INLINE __m128i
|
||||
util_sse2_lerp_epi8_fixed88(__m128i src0, __m128i src1,
|
||||
const __m128i * restrict weight_lo,
|
||||
const __m128i * restrict weight_hi)
|
||||
{
|
||||
const __m128i zero = _mm_setzero_si128();
|
||||
|
||||
__m128i src0_lo = _mm_unpacklo_epi8(src0, zero);
|
||||
__m128i src0_hi = _mm_unpackhi_epi8(src0, zero);
|
||||
|
||||
__m128i src1_lo = _mm_unpacklo_epi8(src1, zero);
|
||||
__m128i src1_hi = _mm_unpackhi_epi8(src1, zero);
|
||||
|
||||
__m128i dst_lo;
|
||||
__m128i dst_hi;
|
||||
|
||||
dst_lo = util_sse2_lerp_epi16(*weight_lo, src0_lo, src1_lo);
|
||||
dst_hi = util_sse2_lerp_epi16(*weight_hi, src0_hi, src1_hi);
|
||||
|
||||
return _mm_packus_epi16(dst_lo, dst_hi);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Linear interpolation with SSE2.
|
||||
*
|
||||
* dst, src0, src1 are 16 x i8 vectors, with [0..255] normalized values.
|
||||
*
|
||||
* weight should be a 16 x i8 vector, in 0.8 fixed point values.
|
||||
*/
|
||||
static ALWAYS_INLINE __m128i
|
||||
util_sse2_lerp_epi8_fixed08(__m128i src0, __m128i src1,
|
||||
__m128i weight)
|
||||
{
|
||||
const __m128i zero = _mm_setzero_si128();
|
||||
__m128i weight_lo = _mm_unpacklo_epi8(weight, zero);
|
||||
__m128i weight_hi = _mm_unpackhi_epi8(weight, zero);
|
||||
|
||||
return util_sse2_lerp_epi8_fixed88(src0, src1,
|
||||
&weight_lo, &weight_hi);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Linear interpolation with SSE2.
|
||||
*
|
||||
* dst, src0, src1, and weight are 16 x i8 vectors, with [0..255] normalized
|
||||
* values.
|
||||
*/
|
||||
static ALWAYS_INLINE __m128i
|
||||
util_sse2_lerp_unorm8(__m128i src0, __m128i src1,
|
||||
__m128i weight)
|
||||
{
|
||||
const __m128i zero = _mm_setzero_si128();
|
||||
__m128i weight_lo = _mm_unpacklo_epi8(weight, zero);
|
||||
__m128i weight_hi = _mm_unpackhi_epi8(weight, zero);
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Rescale from [0..255] to [0..256].
|
||||
*/
|
||||
weight_lo = _mm_add_epi16(weight_lo, _mm_srli_epi16(weight_lo, 7));
|
||||
weight_hi = _mm_add_epi16(weight_hi, _mm_srli_epi16(weight_hi, 7));
|
||||
#endif
|
||||
|
||||
return util_sse2_lerp_epi8_fixed88(src0, src1,
|
||||
&weight_lo, &weight_hi);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Linear interpolation with SSE2.
|
||||
*
|
||||
* dst, src0, src1, src2, src3 are 16 x i8 vectors, with [0..255] normalized
|
||||
* values.
|
||||
*
|
||||
* ws_lo, ws_hi, wt_lo, wt_hi should be a 8 x i16 vectors, in 8.8 fixed point
|
||||
* format, for the low and high components.
|
||||
* We'd want to pass these as values but MSVC limitation forces us to pass these
|
||||
* as pointers since it will complain if more than 3 __m128 are passed by value.
|
||||
*
|
||||
* This uses ws_lo, ws_hi to interpolate between src0 and src1, as well as to
|
||||
* interpolate between src2 and src3, then uses wt_lo and wt_hi to interpolate
|
||||
* between the resulting vectors.
|
||||
*/
|
||||
static ALWAYS_INLINE __m128i
|
||||
util_sse2_lerp_2d_epi8_fixed88(__m128i src0, __m128i src1,
|
||||
const __m128i * restrict src2,
|
||||
const __m128i * restrict src3,
|
||||
const __m128i * restrict ws_lo,
|
||||
const __m128i * restrict ws_hi,
|
||||
const __m128i * restrict wt_lo,
|
||||
const __m128i * restrict wt_hi)
|
||||
{
|
||||
const __m128i zero = _mm_setzero_si128();
|
||||
|
||||
__m128i src0_lo = _mm_unpacklo_epi8(src0, zero);
|
||||
__m128i src0_hi = _mm_unpackhi_epi8(src0, zero);
|
||||
|
||||
__m128i src1_lo = _mm_unpacklo_epi8(src1, zero);
|
||||
__m128i src1_hi = _mm_unpackhi_epi8(src1, zero);
|
||||
|
||||
__m128i src2_lo = _mm_unpacklo_epi8(*src2, zero);
|
||||
__m128i src2_hi = _mm_unpackhi_epi8(*src2, zero);
|
||||
|
||||
__m128i src3_lo = _mm_unpacklo_epi8(*src3, zero);
|
||||
__m128i src3_hi = _mm_unpackhi_epi8(*src3, zero);
|
||||
|
||||
__m128i dst_lo, dst01_lo, dst23_lo;
|
||||
__m128i dst_hi, dst01_hi, dst23_hi;
|
||||
|
||||
dst01_lo = util_sse2_lerp_epi16(*ws_lo, src0_lo, src1_lo);
|
||||
dst01_hi = util_sse2_lerp_epi16(*ws_hi, src0_hi, src1_hi);
|
||||
dst23_lo = util_sse2_lerp_epi16(*ws_lo, src2_lo, src3_lo);
|
||||
dst23_hi = util_sse2_lerp_epi16(*ws_hi, src2_hi, src3_hi);
|
||||
|
||||
dst_lo = util_sse2_lerp_epi16(*wt_lo, dst01_lo, dst23_lo);
|
||||
dst_hi = util_sse2_lerp_epi16(*wt_hi, dst01_hi, dst23_hi);
|
||||
|
||||
return _mm_packus_epi16(dst_lo, dst_hi);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stretch a row of pixels using linear filter.
|
||||
*
|
||||
* Uses Bresenham's line algorithm using 16.16 fixed point representation for
|
||||
* the error term.
|
||||
*
|
||||
* @param dst_width destination width in pixels
|
||||
* @param src_x start x0 in 16.16 fixed point format
|
||||
* @param src_xstep step in 16.16. fixed point format
|
||||
*
|
||||
* @return final src_x value (i.e., src_x + dst_width*src_xstep)
|
||||
*/
|
||||
static ALWAYS_INLINE int32_t
|
||||
util_sse2_stretch_row_8unorm(__m128i * restrict dst,
|
||||
int32_t dst_width,
|
||||
const uint32_t * restrict src,
|
||||
int32_t src_x,
|
||||
int32_t src_xstep)
|
||||
{
|
||||
int16_t error0, error1, error2, error3;
|
||||
__m128i error_lo, error_hi, error_step;
|
||||
|
||||
assert(dst_width >= 0);
|
||||
assert(dst_width % 4 == 0);
|
||||
|
||||
error0 = src_x;
|
||||
error1 = error0 + src_xstep;
|
||||
error2 = error1 + src_xstep;
|
||||
error3 = error2 + src_xstep;
|
||||
|
||||
error_lo = _mm_setr_epi16(error0, error0, error0, error0,
|
||||
error1, error1, error1, error1);
|
||||
error_hi = _mm_setr_epi16(error2, error2, error2, error2,
|
||||
error3, error3, error3, error3);
|
||||
error_step = _mm_set1_epi16(src_xstep << 2);
|
||||
|
||||
dst_width >>= 2;
|
||||
while (dst_width) {
|
||||
uint16_t src_x0;
|
||||
uint16_t src_x1;
|
||||
uint16_t src_x2;
|
||||
uint16_t src_x3;
|
||||
__m128i src0, src1;
|
||||
__m128i weight_lo, weight_hi;
|
||||
|
||||
/*
|
||||
* It is faster to re-compute the coordinates in the scalar integer unit here,
|
||||
* than to fetch the values from the SIMD integer unit.
|
||||
*/
|
||||
|
||||
src_x0 = src_x >> 16;
|
||||
src_x += src_xstep;
|
||||
src_x1 = src_x >> 16;
|
||||
src_x += src_xstep;
|
||||
src_x2 = src_x >> 16;
|
||||
src_x += src_xstep;
|
||||
src_x3 = src_x >> 16;
|
||||
src_x += src_xstep;
|
||||
|
||||
/*
|
||||
* Fetch pairs of pixels 64bit at a time, and then swizzle them inplace.
|
||||
*/
|
||||
|
||||
{
|
||||
__m128i src_00_10 = _mm_loadl_epi64((const __m128i *)&src[src_x0]);
|
||||
__m128i src_01_11 = _mm_loadl_epi64((const __m128i *)&src[src_x1]);
|
||||
__m128i src_02_12 = _mm_loadl_epi64((const __m128i *)&src[src_x2]);
|
||||
__m128i src_03_13 = _mm_loadl_epi64((const __m128i *)&src[src_x3]);
|
||||
|
||||
__m128i src_00_01_10_11 = _mm_unpacklo_epi32(src_00_10, src_01_11);
|
||||
__m128i src_02_03_12_13 = _mm_unpacklo_epi32(src_02_12, src_03_13);
|
||||
|
||||
src0 = _mm_unpacklo_epi64(src_00_01_10_11, src_02_03_12_13);
|
||||
src1 = _mm_unpackhi_epi64(src_00_01_10_11, src_02_03_12_13);
|
||||
}
|
||||
|
||||
weight_lo = _mm_srli_epi16(error_lo, 8);
|
||||
weight_hi = _mm_srli_epi16(error_hi, 8);
|
||||
|
||||
*dst = util_sse2_lerp_epi8_fixed88(src0, src1,
|
||||
&weight_lo, &weight_hi);
|
||||
|
||||
error_lo = _mm_add_epi16(error_lo, error_step);
|
||||
error_hi = _mm_add_epi16(error_hi, error_step);
|
||||
|
||||
++dst;
|
||||
--dst_width;
|
||||
}
|
||||
|
||||
return src_x;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif /* PIPE_ARCH_SSE */
|
||||
|
||||
#endif /* U_SSE_H_ */
|
||||
|
||||
@@ -447,7 +447,7 @@ util_test_constant_buffer(struct pipe_context *ctx,
|
||||
"MOV OUT[0], CONST[0][0]\n"
|
||||
"END\n";
|
||||
struct tgsi_token tokens[1000];
|
||||
struct pipe_shader_state state;
|
||||
struct pipe_shader_state state = {0};
|
||||
|
||||
if (!tgsi_text_translate(text, tokens, ARRAY_SIZE(tokens))) {
|
||||
puts("Can't compile a fragment shader.");
|
||||
@@ -743,7 +743,7 @@ test_texture_barrier(struct pipe_context *ctx, bool use_fbfetch,
|
||||
}
|
||||
|
||||
struct tgsi_token tokens[1000];
|
||||
struct pipe_shader_state state;
|
||||
struct pipe_shader_state state = {0};
|
||||
|
||||
if (!tgsi_text_translate(text, tokens, ARRAY_SIZE(tokens))) {
|
||||
assert(0);
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#include "lp_setup.h"
|
||||
#include "lp_query.h"
|
||||
#include "lp_debug.h"
|
||||
#include "lp_state.h"
|
||||
|
||||
|
||||
/**
|
||||
@@ -57,6 +58,8 @@ llvmpipe_clear(struct pipe_context *pipe,
|
||||
if (!llvmpipe_check_render_cond(llvmpipe))
|
||||
return;
|
||||
|
||||
llvmpipe_update_derived_clear(llvmpipe);
|
||||
|
||||
if (LP_PERF & PERF_NO_DEPTH)
|
||||
buffers &= ~PIPE_CLEAR_DEPTHSTENCIL;
|
||||
|
||||
|
||||
@@ -284,6 +284,9 @@ llvmpipe_create_context(struct pipe_screen *screen, void *priv,
|
||||
draw_wide_point_threshold(llvmpipe->draw, 10000.0);
|
||||
draw_wide_line_threshold(llvmpipe->draw, 10000.0);
|
||||
|
||||
/* initial state for clipping - enabled, with no guardband */
|
||||
draw_set_driver_clipping(llvmpipe->draw, FALSE, FALSE, FALSE, TRUE);
|
||||
|
||||
lp_reset_counters();
|
||||
|
||||
/* If llvmpipe_set_scissor_states() is never called, we still need to
|
||||
|
||||
@@ -156,6 +156,9 @@ struct llvmpipe_context {
|
||||
unsigned nr_fs_variants;
|
||||
unsigned nr_fs_instrs;
|
||||
|
||||
boolean permit_linear_rasterizer;
|
||||
boolean single_vp;
|
||||
|
||||
struct lp_setup_variant_list_item setup_variants_list;
|
||||
unsigned nr_setup_variants;
|
||||
|
||||
|
||||
@@ -47,6 +47,11 @@
|
||||
#define DEBUG_CS 0x10000
|
||||
#define DEBUG_TGSI_IR 0x20000
|
||||
#define DEBUG_CACHE_STATS 0x40000
|
||||
#define DEBUG_NO_FASTPATH 0x80000
|
||||
#define DEBUG_LINEAR 0x100000
|
||||
#define DEBUG_LINEAR2 0x200000
|
||||
#define DEBUG_SHOW_DEPTH 0x400000
|
||||
#define DEBUG_ACCURATE_A0 0x800000 /* verbose */
|
||||
|
||||
/* Performance flags. These are active even on release builds.
|
||||
*/
|
||||
@@ -58,6 +63,8 @@
|
||||
#define PERF_NO_BLEND 0x20 /* disable blending */
|
||||
#define PERF_NO_DEPTH 0x40 /* disable depth buffering entirely */
|
||||
#define PERF_NO_ALPHATEST 0x80 /* disable alpha testing */
|
||||
#define PERF_NO_RAST_LINEAR 0x100 /* disable linear rast */
|
||||
#define PERF_NO_SHADE 0x200 /* disable fragment shaders */
|
||||
|
||||
|
||||
extern int LP_PERF;
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
#include "gallivm/lp_bld_debug.h"
|
||||
#include "gallivm/lp_bld_format.h"
|
||||
#include "lp_context.h"
|
||||
#include "lp_screen.h"
|
||||
#include "lp_jit.h"
|
||||
|
||||
static LLVMTypeRef
|
||||
@@ -189,6 +190,7 @@ lp_jit_create_types(struct lp_fragment_shader_variant *lp)
|
||||
struct gallivm_state *gallivm = lp->gallivm;
|
||||
LLVMContextRef lc = gallivm->context;
|
||||
LLVMTypeRef viewport_type, texture_type, sampler_type, image_type;
|
||||
LLVMTypeRef linear_elem_type;
|
||||
|
||||
/* struct lp_jit_viewport */
|
||||
{
|
||||
@@ -314,6 +316,74 @@ lp_jit_create_types(struct lp_fragment_shader_variant *lp)
|
||||
lp->jit_thread_data_ptr_type = LLVMPointerType(thread_data_type, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* lp_linear_elem
|
||||
*
|
||||
* XXX: it can be instanced only once due to the use of opaque types, and
|
||||
* the fact that screen->module is also a global.
|
||||
*/
|
||||
{
|
||||
LLVMTypeRef ret_type;
|
||||
LLVMTypeRef arg_types[1];
|
||||
LLVMTypeRef func_type;
|
||||
|
||||
ret_type = LLVMPointerType(LLVMVectorType(LLVMInt8TypeInContext(lc), 16), 0);
|
||||
|
||||
arg_types[0] = LLVMPointerType(LLVMInt8TypeInContext(lc), 0);
|
||||
|
||||
/* lp_linear_func */
|
||||
func_type = LLVMFunctionType(ret_type, arg_types, ARRAY_SIZE(arg_types), 0);
|
||||
|
||||
/*
|
||||
* We actually define lp_linear_elem not as a structure but simply as a
|
||||
* lp_linear_func pointer
|
||||
*/
|
||||
linear_elem_type = LLVMPointerType(func_type, 0);
|
||||
}
|
||||
|
||||
/* struct lp_jit_linear_context */
|
||||
{
|
||||
LLVMTypeRef linear_elem_ptr_type = LLVMPointerType(linear_elem_type, 0);
|
||||
LLVMTypeRef elem_types[LP_JIT_LINEAR_CTX_COUNT];
|
||||
LLVMTypeRef linear_context_type;
|
||||
|
||||
|
||||
elem_types[LP_JIT_LINEAR_CTX_CONSTANTS] = LLVMPointerType(LLVMInt8TypeInContext(lc), 0);
|
||||
elem_types[LP_JIT_LINEAR_CTX_TEX] =
|
||||
LLVMArrayType(linear_elem_ptr_type, LP_MAX_LINEAR_TEXTURES);
|
||||
elem_types[LP_JIT_LINEAR_CTX_INPUTS] =
|
||||
LLVMArrayType(linear_elem_ptr_type, LP_MAX_LINEAR_INPUTS);
|
||||
elem_types[LP_JIT_LINEAR_CTX_COLOR0] = LLVMPointerType(LLVMInt8TypeInContext(lc), 0);
|
||||
elem_types[LP_JIT_LINEAR_CTX_BLEND_COLOR] = LLVMInt32TypeInContext(lc);
|
||||
elem_types[LP_JIT_LINEAR_CTX_ALPHA_REF] = LLVMInt8TypeInContext(lc);
|
||||
|
||||
linear_context_type = LLVMStructTypeInContext(lc, elem_types,
|
||||
ARRAY_SIZE(elem_types), 0);
|
||||
|
||||
LP_CHECK_MEMBER_OFFSET(struct lp_jit_linear_context, constants,
|
||||
gallivm->target, linear_context_type,
|
||||
LP_JIT_LINEAR_CTX_CONSTANTS);
|
||||
LP_CHECK_MEMBER_OFFSET(struct lp_jit_linear_context, tex,
|
||||
gallivm->target, linear_context_type,
|
||||
LP_JIT_LINEAR_CTX_TEX);
|
||||
LP_CHECK_MEMBER_OFFSET(struct lp_jit_linear_context, inputs,
|
||||
gallivm->target, linear_context_type,
|
||||
LP_JIT_LINEAR_CTX_INPUTS);
|
||||
LP_CHECK_MEMBER_OFFSET(struct lp_jit_linear_context, color0,
|
||||
gallivm->target, linear_context_type,
|
||||
LP_JIT_LINEAR_CTX_COLOR0);
|
||||
LP_CHECK_MEMBER_OFFSET(struct lp_jit_linear_context, blend_color,
|
||||
gallivm->target, linear_context_type,
|
||||
LP_JIT_LINEAR_CTX_BLEND_COLOR);
|
||||
LP_CHECK_MEMBER_OFFSET(struct lp_jit_linear_context, alpha_ref_value,
|
||||
gallivm->target, linear_context_type,
|
||||
LP_JIT_LINEAR_CTX_ALPHA_REF);
|
||||
LP_CHECK_STRUCT_SIZE(struct lp_jit_linear_context,
|
||||
gallivm->target, linear_context_type);
|
||||
|
||||
lp->jit_linear_context_ptr_type = LLVMPointerType(linear_context_type, 0);
|
||||
}
|
||||
|
||||
if (gallivm_debug & GALLIVM_DEBUG_IR) {
|
||||
char *str = LLVMPrintModuleToString(gallivm->module);
|
||||
fprintf(stderr, "%s", str);
|
||||
|
||||
@@ -324,6 +324,94 @@ typedef void
|
||||
unsigned depth_sample_stride);
|
||||
|
||||
|
||||
#define LP_MAX_LINEAR_CONSTANTS 16
|
||||
#define LP_MAX_LINEAR_TEXTURES 2
|
||||
#define LP_MAX_LINEAR_INPUTS 8
|
||||
|
||||
|
||||
/**
|
||||
* This structure is passed directly to the generated fragment shader.
|
||||
*
|
||||
* It contains the derived state.
|
||||
*
|
||||
* Changes here must be reflected in the lp_jit_linear_context_* macros and
|
||||
* lp_jit_init_types function. Changes to the ordering should be avoided.
|
||||
*
|
||||
* Only use types with a clear size and padding here, in particular prefer the
|
||||
* stdint.h types to the basic integer types.
|
||||
*/
|
||||
struct lp_jit_linear_context
|
||||
{
|
||||
/**
|
||||
* Constants in 8bit unorm values.
|
||||
*/
|
||||
const uint8_t (*constants)[4];
|
||||
struct lp_linear_elem *tex[LP_MAX_LINEAR_TEXTURES];
|
||||
struct lp_linear_elem *inputs[LP_MAX_LINEAR_INPUTS];
|
||||
|
||||
uint8_t *color0;
|
||||
uint32_t blend_color;
|
||||
|
||||
uint8_t alpha_ref_value;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* These enum values must match the position of the fields in the
|
||||
* lp_jit_linear_context struct above.
|
||||
*/
|
||||
enum {
|
||||
LP_JIT_LINEAR_CTX_CONSTANTS = 0,
|
||||
LP_JIT_LINEAR_CTX_TEX,
|
||||
LP_JIT_LINEAR_CTX_INPUTS,
|
||||
LP_JIT_LINEAR_CTX_COLOR0,
|
||||
LP_JIT_LINEAR_CTX_BLEND_COLOR,
|
||||
LP_JIT_LINEAR_CTX_ALPHA_REF,
|
||||
LP_JIT_LINEAR_CTX_COUNT
|
||||
};
|
||||
|
||||
|
||||
#define lp_jit_linear_context_constants(_gallivm, _ptr) \
|
||||
lp_build_struct_get(_gallivm, _ptr, LP_JIT_LINEAR_CTX_CONSTANTS, "constants")
|
||||
|
||||
#define lp_jit_linear_context_tex(_gallivm, _ptr) \
|
||||
lp_build_struct_get_ptr(_gallivm, _ptr, LP_JIT_LINEAR_CTX_TEX, "tex")
|
||||
|
||||
#define lp_jit_linear_context_inputs(_gallivm, _ptr) \
|
||||
lp_build_struct_get_ptr(_gallivm, _ptr, LP_JIT_LINEAR_CTX_INPUTS, "inputs")
|
||||
|
||||
#define lp_jit_linear_context_color0(_gallivm, _ptr) \
|
||||
lp_build_struct_get_ptr(_gallivm, _ptr, LP_JIT_LINEAR_CTX_COLOR0, "color0")
|
||||
|
||||
#define lp_jit_linear_context_blend_color(_gallivm, _ptr) \
|
||||
lp_build_struct_get_ptr(_gallivm, _ptr, LP_JIT_LINEAR_CTX_BLEND_COLOR, "blend_color")
|
||||
|
||||
#define lp_jit_linear_context_alpha_ref(_gallivm, _ptr) \
|
||||
lp_build_struct_get_ptr(_gallivm, _ptr, LP_JIT_LINEAR_CTX_ALPHA_REF, "alpha_ref_value")
|
||||
|
||||
|
||||
typedef const uint8_t *
|
||||
(*lp_jit_linear_llvm_func)(struct lp_jit_linear_context *context,
|
||||
uint32_t x,
|
||||
uint32_t y,
|
||||
uint32_t w);
|
||||
|
||||
/* We're not really jitting this, but I need to get into the
|
||||
* rast_state struct to call the function we actually are jitting.
|
||||
*/
|
||||
struct lp_rast_state;
|
||||
typedef boolean
|
||||
(*lp_jit_linear_func)(const struct lp_rast_state *state,
|
||||
uint32_t x,
|
||||
uint32_t y,
|
||||
uint32_t w,
|
||||
uint32_t h,
|
||||
const float (*a0)[4],
|
||||
const float (*dadx)[4],
|
||||
const float (*dady)[4],
|
||||
uint8_t *color,
|
||||
uint32_t color_stride);
|
||||
|
||||
struct lp_jit_cs_thread_data
|
||||
{
|
||||
struct lp_build_format_cache *cache;
|
||||
|
||||
@@ -69,11 +69,6 @@
|
||||
#define LP_MAX_THREADS 16
|
||||
|
||||
|
||||
/**
|
||||
* Max bytes per scene. This may be replaced by a runtime parameter.
|
||||
*/
|
||||
#define LP_MAX_SCENE_SIZE (512 * 1024 * 1024)
|
||||
|
||||
/**
|
||||
* Max number of shader variants (for all shaders combined,
|
||||
* per context) that will be kept around.
|
||||
|
||||
@@ -0,0 +1,363 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright 2010-2021 VMware, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sub license, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
* USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the
|
||||
* next paragraph) shall be included in all copies or substantial portions
|
||||
* of the Software.
|
||||
*
|
||||
**************************************************************************/
|
||||
|
||||
|
||||
#include "pipe/p_config.h"
|
||||
|
||||
#include "util/u_math.h"
|
||||
#include "util/u_cpu_detect.h"
|
||||
#include "util/u_pack_color.h"
|
||||
#include "util/u_rect.h"
|
||||
#include "util/u_sse.h"
|
||||
|
||||
#include "lp_jit.h"
|
||||
#include "lp_rast.h"
|
||||
#include "lp_debug.h"
|
||||
#include "lp_state_fs.h"
|
||||
#include "lp_linear_priv.h"
|
||||
|
||||
|
||||
#if defined(PIPE_ARCH_SSE)
|
||||
|
||||
|
||||
/* For debugging (LP_DEBUG=linear), shade areas of run-time fallback
|
||||
* purple. Keep blending active so we can see more of what's going
|
||||
* on.
|
||||
*/
|
||||
static boolean
|
||||
linear_fallback(const struct lp_rast_state *state,
|
||||
unsigned x, unsigned y,
|
||||
unsigned width, unsigned height,
|
||||
uint8_t *color,
|
||||
unsigned stride)
|
||||
{
|
||||
unsigned col = 0x808000ff;
|
||||
int i;
|
||||
|
||||
for (y = 0; y < height; y++) {
|
||||
for (i = 0; i < 64; i++) {
|
||||
*((uint32_t *)(color + y*stride) + x + i) = col;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/* Run our configurable linear shader pipeline:
|
||||
*/
|
||||
static boolean
|
||||
lp_fs_linear_run(const struct lp_rast_state *state,
|
||||
unsigned x, unsigned y,
|
||||
unsigned width, unsigned height,
|
||||
const float (*a0)[4],
|
||||
const float (*dadx)[4],
|
||||
const float (*dady)[4],
|
||||
uint8_t *color,
|
||||
unsigned stride)
|
||||
{
|
||||
const struct lp_fragment_shader_variant *variant = state->variant;
|
||||
const struct lp_tgsi_info *info = &variant->shader->info;
|
||||
struct lp_jit_linear_context jit;
|
||||
lp_jit_linear_llvm_func jit_func = variant->jit_linear_llvm;
|
||||
|
||||
struct lp_linear_sampler samp[LP_MAX_LINEAR_TEXTURES];
|
||||
struct lp_linear_interp interp[LP_MAX_LINEAR_INPUTS];
|
||||
uint8_t constants[LP_MAX_LINEAR_CONSTANTS][4];
|
||||
|
||||
const float w0 = a0[0][3];
|
||||
float oow = 1.0f/w0;
|
||||
|
||||
unsigned input_mask = variant->linear_input_mask;
|
||||
int nr_consts = info->base.file_max[TGSI_FILE_CONSTANT]+1;
|
||||
int nr_tex = info->num_texs;
|
||||
int i, j;
|
||||
|
||||
LP_DBG(DEBUG_RAST, "%s\n", __FUNCTION__);
|
||||
|
||||
/* Require constant w in these rectangles:
|
||||
*/
|
||||
if (dadx[0][3] != 0.0f ||
|
||||
dady[0][3] != 0.0f) {
|
||||
if (LP_DEBUG & DEBUG_LINEAR2)
|
||||
debug_printf(" -- w not constant\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* XXX: Per statechange:
|
||||
*/
|
||||
for (i = 0; i < nr_consts; i++) {
|
||||
for (j = 0; j < 4; j++) {
|
||||
float val = state->jit_context.constants[0][i*4+j];
|
||||
if (val < 0.0f || val > 1.0f) {
|
||||
if (LP_DEBUG & DEBUG_LINEAR2)
|
||||
debug_printf(" -- const[%d] out of range\n", i);
|
||||
goto fail;
|
||||
}
|
||||
constants[i][j] = (uint8_t)(val * 255.0f);
|
||||
}
|
||||
}
|
||||
jit.constants = (const uint8_t (*)[4])constants;
|
||||
|
||||
/* We assume BGRA ordering */
|
||||
assert(variant->key.cbuf_format[0] == PIPE_FORMAT_B8G8R8X8_UNORM ||
|
||||
variant->key.cbuf_format[0] == PIPE_FORMAT_B8G8R8A8_UNORM);
|
||||
|
||||
jit.blend_color =
|
||||
state->jit_context.u8_blend_color[32] +
|
||||
(state->jit_context.u8_blend_color[16] << 8) +
|
||||
(state->jit_context.u8_blend_color[0] << 16) +
|
||||
(state->jit_context.u8_blend_color[48] << 24);
|
||||
|
||||
jit.alpha_ref_value = float_to_ubyte(state->jit_context.alpha_ref_value);
|
||||
|
||||
/* XXX: Per primitive:
|
||||
*/
|
||||
while (input_mask) {
|
||||
int i = u_bit_scan(&input_mask);
|
||||
unsigned usage_mask = info->base.input_usage_mask[i];
|
||||
boolean perspective =
|
||||
info->base.input_interpolate[i] == TGSI_INTERPOLATE_PERSPECTIVE ||
|
||||
(info->base.input_interpolate[i] == TGSI_INTERPOLATE_COLOR &&
|
||||
!variant->key.flatshade);
|
||||
|
||||
if (!lp_linear_init_interp(&interp[i],
|
||||
x, y, width, height,
|
||||
usage_mask,
|
||||
perspective,
|
||||
oow,
|
||||
a0[i+1],
|
||||
dadx[i+1],
|
||||
dady[i+1])) {
|
||||
if (LP_DEBUG & DEBUG_LINEAR2)
|
||||
debug_printf(" -- init_interp(%d) failed\n", i);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
jit.inputs[i] = &interp[i].base;
|
||||
}
|
||||
|
||||
|
||||
/* XXX: Per primitive: Initialize linear or nearest samplers:
|
||||
*/
|
||||
for (i = 0; i < nr_tex; i++) {
|
||||
const struct lp_tgsi_texture_info *tex_info = &info->tex[i];
|
||||
unsigned unit = tex_info->sampler_unit;
|
||||
|
||||
/* XXX: some texture coordinates are linear!
|
||||
*/
|
||||
//boolean perspective = (info->base.input_interpolate[i] ==
|
||||
// TGSI_INTERPOLATE_PERSPECTIVE);
|
||||
|
||||
if (!lp_linear_init_sampler(&samp[i],
|
||||
tex_info,
|
||||
&variant->key.samplers[unit],
|
||||
&state->jit_context.textures[unit],
|
||||
x, y, width, height,
|
||||
a0, dadx, dady)) {
|
||||
if (LP_DEBUG & DEBUG_LINEAR2)
|
||||
debug_printf(" -- init_sampler(%d) failed\n", i);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
jit.tex[i] = &samp[i].base;
|
||||
}
|
||||
|
||||
/* JIT function already does blending */
|
||||
jit.color0 = color + x * 4 + y * stride;
|
||||
for (y = 0; y < height; y++) {
|
||||
jit_func(&jit, 0, 0, width);
|
||||
jit.color0 += stride;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
||||
fail:
|
||||
/* Visually distinguish this from other fallbacks:
|
||||
*/
|
||||
if (LP_DEBUG & DEBUG_LINEAR) {
|
||||
return linear_fallback(state, x, y, width, height, color, stride);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
check_linear_interp_mask_a(struct lp_fragment_shader_variant *variant)
|
||||
{
|
||||
const struct lp_tgsi_info *info = &variant->shader->info;
|
||||
struct lp_jit_linear_context jit;
|
||||
|
||||
struct lp_linear_sampler samp[LP_MAX_LINEAR_TEXTURES];
|
||||
struct lp_linear_interp interp[LP_MAX_LINEAR_INPUTS];
|
||||
uint8_t constants[LP_MAX_LINEAR_CONSTANTS][4];
|
||||
PIPE_ALIGN_VAR(16) uint8_t color0[TILE_SIZE*4];
|
||||
|
||||
int nr_inputs = info->base.file_max[TGSI_FILE_INPUT]+1;
|
||||
int nr_tex = info->num_texs;
|
||||
int i;
|
||||
|
||||
LP_DBG(DEBUG_RAST, "%s\n", __FUNCTION__);
|
||||
|
||||
jit.constants = (const uint8_t (*)[4])constants;
|
||||
|
||||
for (i = 0; i < nr_tex; i++) {
|
||||
lp_linear_init_noop_sampler(&samp[i]);
|
||||
jit.tex[i] = &samp[i].base;
|
||||
}
|
||||
|
||||
for (i = 0; i < nr_inputs; i++) {
|
||||
lp_linear_init_noop_interp(&interp[i]);
|
||||
jit.inputs[i] = &interp[i].base;
|
||||
}
|
||||
|
||||
jit.color0 = color0;
|
||||
|
||||
(void)variant->jit_linear_llvm(&jit, 0, 0, 0);
|
||||
|
||||
/* Find out which interpolators were called, and store this as a
|
||||
* mask:
|
||||
*/
|
||||
for (i = 0; i < nr_inputs; i++)
|
||||
variant->linear_input_mask |= (interp[i].row[0] << i);
|
||||
}
|
||||
|
||||
|
||||
/* Until the above is working, look at texture information and guess
|
||||
* that any input used as a texture coordinate is not used for
|
||||
* anything else.
|
||||
*/
|
||||
static void
|
||||
check_linear_interp_mask_b(struct lp_fragment_shader_variant *variant)
|
||||
{
|
||||
const struct lp_tgsi_info *info = &variant->shader->info;
|
||||
int nr_inputs = info->base.file_max[TGSI_FILE_INPUT]+1;
|
||||
int nr_tex = info->num_texs;
|
||||
unsigned tex_mask = 0;
|
||||
int i;
|
||||
|
||||
LP_DBG(DEBUG_RAST, "%s\n", __FUNCTION__);
|
||||
|
||||
for (i = 0; i < nr_tex; i++) {
|
||||
const struct lp_tgsi_texture_info *tex_info = &info->tex[i];
|
||||
const struct lp_tgsi_channel_info *schan = &tex_info->coord[0];
|
||||
const struct lp_tgsi_channel_info *tchan = &tex_info->coord[1];
|
||||
tex_mask |= 1 << schan->u.index;
|
||||
tex_mask |= 1 << tchan->u.index;
|
||||
}
|
||||
|
||||
variant->linear_input_mask = ((1 << nr_inputs) - 1) & ~tex_mask;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lp_linear_check_variant(struct lp_fragment_shader_variant *variant)
|
||||
{
|
||||
const struct lp_fragment_shader_variant_key *key = &variant->key;
|
||||
const struct lp_fragment_shader *shader = variant->shader;
|
||||
const struct lp_tgsi_info *info = &shader->info;
|
||||
int i;
|
||||
|
||||
if (info->base.file_max[TGSI_FILE_CONSTANT] >= LP_MAX_LINEAR_CONSTANTS ||
|
||||
info->base.file_max[TGSI_FILE_INPUT] >= LP_MAX_LINEAR_INPUTS) {
|
||||
if (LP_DEBUG & DEBUG_LINEAR)
|
||||
debug_printf(" -- too many inputs/constants\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* If we have a fastpath which implements the entire varient, use
|
||||
* that.
|
||||
*/
|
||||
if (lp_linear_check_fastpath(variant)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Otherwise, can we build up a spanline-based linear path for this
|
||||
* variant?
|
||||
*/
|
||||
|
||||
/* Check static sampler state.
|
||||
*/
|
||||
for (i = 0; i < info->num_texs; i++) {
|
||||
const struct lp_tgsi_texture_info *tex_info = &info->tex[i];
|
||||
unsigned unit = tex_info->sampler_unit;
|
||||
|
||||
/* XXX: Relax this once setup premultiplies by oow:
|
||||
*/
|
||||
if (info->base.input_interpolate[unit] != TGSI_INTERPOLATE_PERSPECTIVE) {
|
||||
if (LP_DEBUG & DEBUG_LINEAR)
|
||||
debug_printf(" -- samp[%d]: texcoord not perspective\n", i);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!lp_linear_check_sampler(&key->samplers[unit], tex_info)) {
|
||||
if (LP_DEBUG & DEBUG_LINEAR)
|
||||
debug_printf(" -- samp[%d]: check_sampler failed\n", i);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check shader. May not have been jitted.
|
||||
*/
|
||||
if (variant->linear_function == NULL) {
|
||||
if (LP_DEBUG & DEBUG_LINEAR)
|
||||
debug_printf(" -- no linear shader\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Hook in the catchall shader runner:
|
||||
*/
|
||||
variant->jit_linear = lp_fs_linear_run;
|
||||
|
||||
/* Figure out which inputs we don't need to interpolate (because
|
||||
* they are only used as texture coordinates). This is important
|
||||
* as we can cope with texture coordinates which exceed 1.0, but
|
||||
* cannot do so for regular inputs.
|
||||
*/
|
||||
if (1)
|
||||
check_linear_interp_mask_a(variant);
|
||||
else
|
||||
check_linear_interp_mask_b(variant);
|
||||
|
||||
|
||||
if (0) {
|
||||
lp_debug_fs_variant(variant);
|
||||
debug_printf("linear input mask: 0x%x\n", variant->linear_input_mask);
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
fail:
|
||||
if (LP_DEBUG & DEBUG_LINEAR) {
|
||||
lp_debug_fs_variant(variant);
|
||||
debug_printf(" ----> no linear path for this variant\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,237 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright 2010-2021 VMware, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sub license, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
* USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the
|
||||
* next paragraph) shall be included in all copies or substantial portions
|
||||
* of the Software.
|
||||
*
|
||||
**************************************************************************/
|
||||
|
||||
|
||||
#include "pipe/p_config.h"
|
||||
|
||||
#include "util/u_math.h"
|
||||
#include "util/u_cpu_detect.h"
|
||||
#include "util/u_pack_color.h"
|
||||
#include "util/u_surface.h"
|
||||
#include "util/u_sse.h"
|
||||
|
||||
#include "lp_jit.h"
|
||||
#include "lp_rast.h"
|
||||
#include "lp_debug.h"
|
||||
#include "lp_state_fs.h"
|
||||
#include "lp_linear_priv.h"
|
||||
|
||||
|
||||
#if defined(PIPE_ARCH_SSE)
|
||||
|
||||
|
||||
/* This file contains various special-case fastpaths which implement
|
||||
* the entire linear pipeline in a single funciton.
|
||||
*
|
||||
* These include simple blits and some debug code.
|
||||
*
|
||||
* These functions fully implement the linear path and do not need to
|
||||
* be combined with blending, interpolation or sampling routines.
|
||||
*/
|
||||
|
||||
/* Linear shader which implements the BLIT_RGBA shader with the
|
||||
* additional constraints imposed by lp_setup_is_blit().
|
||||
*/
|
||||
static boolean
|
||||
lp_linear_blit_rgba_blit(const struct lp_rast_state *state,
|
||||
unsigned x, unsigned y,
|
||||
unsigned width, unsigned height,
|
||||
const float (*a0)[4],
|
||||
const float (*dadx)[4],
|
||||
const float (*dady)[4],
|
||||
uint8_t *color,
|
||||
unsigned stride)
|
||||
{
|
||||
const struct lp_jit_context *context = &state->jit_context;
|
||||
const struct lp_jit_texture *texture = &context->textures[0];
|
||||
const uint8_t *src;
|
||||
unsigned src_stride;
|
||||
int src_x, src_y;
|
||||
|
||||
LP_DBG(DEBUG_RAST, "%s\n", __FUNCTION__);
|
||||
|
||||
/* Require w==1.0:
|
||||
*/
|
||||
if (a0[0][3] != 1.0 ||
|
||||
dadx[0][3] != 0.0 ||
|
||||
dady[0][3] != 0.0)
|
||||
return FALSE;
|
||||
|
||||
src_x = x + util_iround(a0[1][0]*texture->width - 0.5f);
|
||||
src_y = y + util_iround(a0[1][1]*texture->height - 0.5f);
|
||||
|
||||
src = texture->base;
|
||||
src_stride = texture->row_stride[0];
|
||||
|
||||
/* Fall back to blit_rgba() if clamping required:
|
||||
*/
|
||||
if (src_x < 0 ||
|
||||
src_y < 0 ||
|
||||
src_x + width > texture->width ||
|
||||
src_y + height > texture->height)
|
||||
return FALSE;
|
||||
|
||||
util_copy_rect(color, PIPE_FORMAT_B8G8R8A8_UNORM, stride,
|
||||
x, y,
|
||||
width, height,
|
||||
src, src_stride,
|
||||
src_x, src_y);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/* Linear shader which implements the BLIT_RGB1 shader, with the
|
||||
* additional constraints imposed by lp_setup_is_blit().
|
||||
*/
|
||||
static boolean
|
||||
lp_linear_blit_rgb1_blit(const struct lp_rast_state *state,
|
||||
unsigned x, unsigned y,
|
||||
unsigned width, unsigned height,
|
||||
const float (*a0)[4],
|
||||
const float (*dadx)[4],
|
||||
const float (*dady)[4],
|
||||
uint8_t *color,
|
||||
unsigned stride)
|
||||
{
|
||||
const struct lp_jit_context *context = &state->jit_context;
|
||||
const struct lp_jit_texture *texture = &context->textures[0];
|
||||
const uint8_t *src;
|
||||
unsigned src_stride;
|
||||
int src_x, src_y;
|
||||
|
||||
LP_DBG(DEBUG_RAST, "%s\n", __FUNCTION__);
|
||||
|
||||
/* Require w==1.0:
|
||||
*/
|
||||
if (a0[0][3] != 1.0 ||
|
||||
dadx[0][3] != 0.0 ||
|
||||
dady[0][3] != 0.0)
|
||||
return FALSE;
|
||||
|
||||
color += x * 4 + y * stride;
|
||||
|
||||
src_x = x + util_iround(a0[1][0]*texture->width - 0.5f);
|
||||
src_y = y + util_iround(a0[1][1]*texture->height - 0.5f);
|
||||
|
||||
src = texture->base;
|
||||
src_stride = texture->row_stride[0];
|
||||
src += src_x * 4;
|
||||
src += src_y * src_stride;
|
||||
|
||||
if (src_x < 0 ||
|
||||
src_y < 0 ||
|
||||
src_x + width > texture->width ||
|
||||
src_y + height > texture->height)
|
||||
return FALSE;
|
||||
|
||||
for (y = 0; y < height; y++) {
|
||||
const uint32_t *src_row = (const uint32_t *)src;
|
||||
uint32_t *dst_row = (uint32_t *)color;
|
||||
|
||||
for (x = 0; x < width; x++) {
|
||||
*dst_row++ = *src_row++ | 0xff000000;
|
||||
}
|
||||
|
||||
color += stride;
|
||||
src += src_stride;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Linear shader which always emits purple. Used for debugging.
|
||||
*/
|
||||
static boolean
|
||||
lp_linear_purple(const struct lp_rast_state *state,
|
||||
unsigned x, unsigned y,
|
||||
unsigned width, unsigned height,
|
||||
const float (*a0)[4],
|
||||
const float (*dadx)[4],
|
||||
const float (*dady)[4],
|
||||
uint8_t *color,
|
||||
unsigned stride)
|
||||
{
|
||||
union util_color uc;
|
||||
|
||||
util_pack_color_ub(0xff, 0, 0xff, 0xff,
|
||||
PIPE_FORMAT_B8G8R8A8_UNORM, &uc);
|
||||
|
||||
util_fill_rect(color,
|
||||
PIPE_FORMAT_B8G8R8A8_UNORM,
|
||||
stride,
|
||||
x,
|
||||
y,
|
||||
width,
|
||||
height,
|
||||
&uc);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Examine the fragment shader varient and determine whether we can
|
||||
* substitute a fastpath linear shader implementation.
|
||||
*/
|
||||
boolean
|
||||
lp_linear_check_fastpath(struct lp_fragment_shader_variant *variant)
|
||||
{
|
||||
enum pipe_format tex_format = variant->key.samplers[0].texture_state.format;
|
||||
|
||||
if (variant->shader->kind == LP_FS_KIND_BLIT_RGBA &&
|
||||
tex_format == PIPE_FORMAT_B8G8R8A8_UNORM &&
|
||||
is_nearest_clamp_sampler(&variant->key.samplers[0]) &&
|
||||
variant->opaque) {
|
||||
variant->jit_linear_blit = lp_linear_blit_rgba_blit;
|
||||
}
|
||||
|
||||
if (variant->shader->kind == LP_FS_KIND_BLIT_RGB1 &&
|
||||
variant->opaque &&
|
||||
(tex_format == PIPE_FORMAT_B8G8R8A8_UNORM ||
|
||||
tex_format == PIPE_FORMAT_B8G8R8X8_UNORM) &&
|
||||
is_nearest_clamp_sampler(&variant->key.samplers[0])) {
|
||||
variant->jit_linear_blit = lp_linear_blit_rgb1_blit;
|
||||
}
|
||||
|
||||
if (0) {
|
||||
variant->jit_linear = lp_linear_purple;
|
||||
}
|
||||
|
||||
|
||||
/* Stop now if jit_linear has been initialized. Otherwise keep
|
||||
* searching - even if jit_linear_blit has been instantiated.
|
||||
*/
|
||||
return variant->jit_linear != NULL;
|
||||
}
|
||||
#else
|
||||
void
|
||||
boolean
|
||||
lp_linear_check_fastpath(struct lp_fragment_shader_variant *variant)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,243 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright 2010-2021 VMware, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sub license, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
* USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the
|
||||
* next paragraph) shall be included in all copies or substantial portions
|
||||
* of the Software.
|
||||
*
|
||||
**************************************************************************/
|
||||
|
||||
|
||||
#include "pipe/p_config.h"
|
||||
|
||||
#include "util/u_math.h"
|
||||
#include "util/u_cpu_detect.h"
|
||||
#include "util/u_pack_color.h"
|
||||
#include "util/u_rect.h"
|
||||
#include "util/u_sse.h"
|
||||
|
||||
#include "lp_jit.h"
|
||||
#include "lp_rast.h"
|
||||
#include "lp_debug.h"
|
||||
#include "lp_state_fs.h"
|
||||
#include "lp_linear_priv.h"
|
||||
|
||||
|
||||
#if defined(PIPE_ARCH_SSE)
|
||||
|
||||
#define FIXED15_ONE 0x7fff
|
||||
|
||||
/* Translate floating point value to 1.15 unsigned fixed-point.
|
||||
*/
|
||||
static inline ushort
|
||||
float_to_ufixed_1_15(float f)
|
||||
{
|
||||
return CLAMP((unsigned)(f * (float)FIXED15_ONE), 0, FIXED15_ONE);
|
||||
}
|
||||
|
||||
|
||||
/* Translate floating point value to 1.15 signed fixed-point.
|
||||
*/
|
||||
static inline int16_t
|
||||
float_to_sfixed_1_15(float f)
|
||||
{
|
||||
return CLAMP((signed)(f * (float)FIXED15_ONE), -FIXED15_ONE, FIXED15_ONE);
|
||||
}
|
||||
|
||||
|
||||
/* Interpolate in 1.15 space, but produce a packed row of 0.8 values.
|
||||
*/
|
||||
static const uint32_t *
|
||||
interp_0_8(struct lp_linear_elem *elem)
|
||||
{
|
||||
struct lp_linear_interp *interp = (struct lp_linear_interp *)elem;
|
||||
uint32_t *row = interp->row;
|
||||
__m128i a0 = interp->a0;
|
||||
__m128i dadx = interp->dadx;
|
||||
int width = (interp->width + 3) & ~3;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < width; i += 4) {
|
||||
__m128i l, h;
|
||||
|
||||
l = _mm_srai_epi16(a0, 7);
|
||||
a0 = _mm_add_epi16(a0, dadx);
|
||||
|
||||
h = _mm_srai_epi16(a0, 7);
|
||||
a0 = _mm_add_epi16(a0, dadx);
|
||||
|
||||
*(__m128i *)&row[i] = _mm_packus_epi16(l, h);
|
||||
}
|
||||
|
||||
interp->a0 = _mm_add_epi16(interp->a0, interp->dady);
|
||||
return interp->row;
|
||||
}
|
||||
|
||||
static const uint32_t *
|
||||
interp_noop(struct lp_linear_elem *elem)
|
||||
{
|
||||
struct lp_linear_interp *interp = (struct lp_linear_interp *)elem;
|
||||
return interp->row;
|
||||
}
|
||||
|
||||
|
||||
static const uint32_t *
|
||||
interp_check(struct lp_linear_elem *elem)
|
||||
{
|
||||
struct lp_linear_interp *interp = (struct lp_linear_interp *)elem;
|
||||
interp->row[0] = 1;
|
||||
return interp->row;
|
||||
}
|
||||
|
||||
/* Not quite a noop - we use row[0] to track whether this gets called
|
||||
* or not, so we can optimize which interpolants we care about.
|
||||
*/
|
||||
void
|
||||
lp_linear_init_noop_interp(struct lp_linear_interp *interp)
|
||||
{
|
||||
interp->row[0] = 0;
|
||||
interp->base.fetch = interp_check;
|
||||
}
|
||||
|
||||
boolean
|
||||
lp_linear_init_interp(struct lp_linear_interp *interp,
|
||||
int x, int y, int width, int height,
|
||||
unsigned usage_mask,
|
||||
boolean perspective,
|
||||
float oow,
|
||||
const float *a0,
|
||||
const float *dadx,
|
||||
const float *dady)
|
||||
{
|
||||
float s0[4];
|
||||
float dsdx[4];
|
||||
float dsdy[4];
|
||||
int16_t s0_fp[8];
|
||||
int16_t dsdx_fp[4];
|
||||
int16_t dsdy_fp[4];
|
||||
int j;
|
||||
|
||||
/* Zero coefficients to avoid using uninitialised values */
|
||||
memset(s0, 0, sizeof(s0));
|
||||
memset(dsdx, 0, sizeof(dsdx));
|
||||
memset(dsdy, 0, sizeof(dsdy));
|
||||
memset(s0_fp, 0, sizeof(s0_fp));
|
||||
memset(dsdx_fp, 0, sizeof(dsdx_fp));
|
||||
memset(dsdy_fp, 0, sizeof(dsdy_fp));
|
||||
|
||||
if (perspective) {
|
||||
for (j = 0; j < 4; j++) {
|
||||
if (usage_mask & (1<<j)) {
|
||||
s0[j] = a0[j] * oow;
|
||||
dsdx[j] = dadx[j] * oow;
|
||||
dsdy[j] = dady[j] * oow;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (j = 0; j < 4; j++) {
|
||||
if (usage_mask & (1<<j)) {
|
||||
s0[j] = a0[j];
|
||||
dsdx[j] = dadx[j];
|
||||
dsdy[j] = dady[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s0[0] += x * dsdx[0] + y * dsdy[0];
|
||||
s0[1] += x * dsdx[1] + y * dsdy[1];
|
||||
s0[2] += x * dsdx[2] + y * dsdy[2];
|
||||
s0[3] += x * dsdx[3] + y * dsdy[3];
|
||||
|
||||
/* XXX: lift all of this into the rectangle setup code.
|
||||
*
|
||||
* For rectangles with linear shaders, at setup time:
|
||||
* - if w is constant (else mark as non-fastpath)
|
||||
* - premultiply perspective interpolants by w
|
||||
* - set w = 1 in position
|
||||
* - check all interpolants for min/max 0..1 (else mark as
|
||||
* non-fastpath)
|
||||
*/
|
||||
for (j = 0; j < 4; j++) {
|
||||
if (usage_mask & (1<<j)) {
|
||||
float a = s0[j];
|
||||
float b = s0[j] + (width - 1) * dsdx[j];
|
||||
float c = s0[j] + (height - 1) * dsdy[j];
|
||||
float d = s0[j] + (height - 1) * dsdy[j] + (width - 1) * dsdx[j];
|
||||
|
||||
if (MIN4(a,b,c,d) < 0.0)
|
||||
FAIL("min < 0.0");
|
||||
|
||||
if (MAX4(a,b,c,d) > 1.0)
|
||||
FAIL("max > 1.0");
|
||||
|
||||
dsdx_fp[j] = float_to_sfixed_1_15(dsdx[j]);
|
||||
dsdy_fp[j] = float_to_sfixed_1_15(dsdy[j]);
|
||||
|
||||
s0_fp[j] = float_to_ufixed_1_15(s0[j]);
|
||||
s0_fp[j + 4] = s0_fp[j] + dsdx_fp[j];
|
||||
|
||||
dsdx_fp[j] *= 2;
|
||||
}
|
||||
}
|
||||
|
||||
interp->width = align(width, 4);
|
||||
|
||||
interp->a0 = _mm_setr_epi16(s0_fp[2], s0_fp[1], s0_fp[0], s0_fp[3],
|
||||
s0_fp[6], s0_fp[5], s0_fp[4], s0_fp[7]);
|
||||
|
||||
interp->dadx = _mm_setr_epi16(dsdx_fp[2], dsdx_fp[1], dsdx_fp[0], dsdx_fp[3],
|
||||
dsdx_fp[2], dsdx_fp[1], dsdx_fp[0], dsdx_fp[3]);
|
||||
|
||||
interp->dady = _mm_setr_epi16(dsdy_fp[2], dsdy_fp[1], dsdy_fp[0], dsdy_fp[3],
|
||||
dsdy_fp[2], dsdy_fp[1], dsdy_fp[0], dsdy_fp[3]);
|
||||
|
||||
/* If the value is y-invariant, eagerly calculate it here and then
|
||||
* always return the precalculated value.
|
||||
*/
|
||||
if (dsdy[0] == 0 &&
|
||||
dsdy[1] == 0 &&
|
||||
dsdy[2] == 0 &&
|
||||
dsdy[3] == 0)
|
||||
{
|
||||
interp_0_8(&interp->base);
|
||||
interp->base.fetch = interp_noop;
|
||||
}
|
||||
else {
|
||||
interp->base.fetch = interp_0_8;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#else
|
||||
boolean
|
||||
lp_linear_init_interp(struct lp_linear_interp *interp,
|
||||
int x, int y, int width, int height,
|
||||
unsigned usage_mask,
|
||||
boolean perspective,
|
||||
float oow,
|
||||
const float *a0,
|
||||
const float *dadx,
|
||||
const float *dady)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,169 @@
|
||||
|
||||
#ifndef LP_LINEAR_PRIV_H
|
||||
#define LP_LINEAR_PRIV_H
|
||||
|
||||
struct lp_linear_elem;
|
||||
|
||||
typedef const uint32_t *(*lp_linear_func)(struct lp_linear_elem *base);
|
||||
|
||||
|
||||
struct lp_linear_elem {
|
||||
lp_linear_func fetch;
|
||||
};
|
||||
|
||||
|
||||
/* "Linear" refers to the fact we're on the linear (non-swizzled)
|
||||
* rasterization path. Filtering mode may be either linear or
|
||||
* nearest.
|
||||
*/
|
||||
struct lp_linear_sampler {
|
||||
struct lp_linear_elem base;
|
||||
|
||||
const struct lp_jit_texture *texture;
|
||||
int s; /* 16.16, biased by .5 */
|
||||
int t; /* 16.16, biased by .5 */
|
||||
int dsdx; /* 16.16 */
|
||||
int dsdy; /* 16.16 */
|
||||
int dtdx; /* 16.16 */
|
||||
int dtdy; /* 16.16 */
|
||||
int width;
|
||||
boolean axis_aligned;
|
||||
|
||||
PIPE_ALIGN_VAR(16) uint32_t row[64];
|
||||
PIPE_ALIGN_VAR(16) uint32_t stretched_row[2][64];
|
||||
|
||||
/**
|
||||
* y coordinate of the rows stored in the stretched_row.
|
||||
*
|
||||
* Negative number means no stretched row is cached.
|
||||
*/
|
||||
int stretched_row_y[2];
|
||||
|
||||
/**
|
||||
* The index of stretched_row to receive the next stretched row.
|
||||
*/
|
||||
int stretched_row_index;
|
||||
};
|
||||
|
||||
/* "Linear" refers to the fact we're on the linear (non-swizzled)
|
||||
* rasterization path. Interpolation mode may be either constant,
|
||||
* linear or perspective.
|
||||
*/
|
||||
struct lp_linear_interp {
|
||||
struct lp_linear_elem base;
|
||||
|
||||
__m128i a0;
|
||||
__m128i dadx;
|
||||
__m128i dady;
|
||||
|
||||
int width; /* rounded up to multiple of 4 */
|
||||
|
||||
PIPE_ALIGN_VAR(16) uint32_t row[64];
|
||||
};
|
||||
|
||||
|
||||
/* Check for a sampler variant which matches our fetch_row
|
||||
* implementation - normalized texcoords, single mipmap with
|
||||
* nearest filtering.
|
||||
*/
|
||||
static inline boolean
|
||||
is_nearest_sampler(const struct lp_sampler_static_state *sampler)
|
||||
{
|
||||
return
|
||||
sampler->texture_state.target == PIPE_TEXTURE_2D &&
|
||||
sampler->sampler_state.min_img_filter == PIPE_TEX_FILTER_NEAREST &&
|
||||
sampler->sampler_state.mag_img_filter == PIPE_TEX_FILTER_NEAREST &&
|
||||
(sampler->texture_state.level_zero_only ||
|
||||
sampler->sampler_state.min_mip_filter == PIPE_TEX_MIPFILTER_NONE) &&
|
||||
sampler->sampler_state.compare_mode == 0 &&
|
||||
sampler->sampler_state.normalized_coords == 1;
|
||||
}
|
||||
|
||||
|
||||
/* Check for a sampler variant which matches our fetch_row
|
||||
* implementation - normalized texcoords, single mipmap with
|
||||
* linear filtering.
|
||||
*/
|
||||
static inline boolean
|
||||
is_linear_sampler(const struct lp_sampler_static_state *sampler)
|
||||
{
|
||||
return
|
||||
sampler->texture_state.target == PIPE_TEXTURE_2D &&
|
||||
sampler->sampler_state.min_img_filter == PIPE_TEX_FILTER_LINEAR &&
|
||||
sampler->sampler_state.mag_img_filter == PIPE_TEX_FILTER_LINEAR &&
|
||||
(sampler->texture_state.level_zero_only ||
|
||||
sampler->sampler_state.min_mip_filter == PIPE_TEX_MIPFILTER_NONE) &&
|
||||
sampler->sampler_state.compare_mode == 0 &&
|
||||
sampler->sampler_state.normalized_coords == 1;
|
||||
}
|
||||
|
||||
|
||||
/* Check for a sampler variant which matches is_nearest_sampler
|
||||
* but has the additional constraints of using clamp wrapping
|
||||
*/
|
||||
static inline boolean
|
||||
is_nearest_clamp_sampler(const struct lp_sampler_static_state *sampler)
|
||||
{
|
||||
return
|
||||
is_nearest_sampler(sampler) &&
|
||||
sampler->sampler_state.wrap_s == PIPE_TEX_WRAP_CLAMP_TO_EDGE &&
|
||||
sampler->sampler_state.wrap_t == PIPE_TEX_WRAP_CLAMP_TO_EDGE;
|
||||
}
|
||||
|
||||
|
||||
/* Check for a sampler variant which matches is_linear_sampler
|
||||
* but has the additional constraints of using clamp wrapping
|
||||
*/
|
||||
static inline boolean
|
||||
is_linear_clamp_sampler(const struct lp_sampler_static_state *sampler)
|
||||
{
|
||||
return
|
||||
is_linear_sampler(sampler) &&
|
||||
sampler->sampler_state.wrap_s == PIPE_TEX_WRAP_CLAMP_TO_EDGE &&
|
||||
sampler->sampler_state.wrap_t == PIPE_TEX_WRAP_CLAMP_TO_EDGE;
|
||||
}
|
||||
|
||||
|
||||
boolean
|
||||
lp_linear_init_interp(struct lp_linear_interp *interp,
|
||||
int x, int y, int width, int height,
|
||||
unsigned usage_mask,
|
||||
boolean perspective,
|
||||
float oow,
|
||||
const float *a0,
|
||||
const float *dadx,
|
||||
const float *dady);
|
||||
|
||||
boolean
|
||||
lp_linear_init_sampler(struct lp_linear_sampler *samp,
|
||||
const struct lp_tgsi_texture_info *info,
|
||||
const struct lp_sampler_static_state *sampler_state,
|
||||
const struct lp_jit_texture *texture,
|
||||
int x0, int y0, int width, int height,
|
||||
const float (*a0)[4],
|
||||
const float (*dadx)[4],
|
||||
const float (*dady)[4]);
|
||||
|
||||
|
||||
boolean
|
||||
lp_linear_check_fastpath(struct lp_fragment_shader_variant *variant);
|
||||
|
||||
boolean
|
||||
lp_linear_check_sampler(const struct lp_sampler_static_state *sampler,
|
||||
const struct lp_tgsi_texture_info *tex);
|
||||
|
||||
|
||||
void
|
||||
lp_linear_init_noop_interp(struct lp_linear_interp *interp);
|
||||
|
||||
void
|
||||
lp_linear_init_noop_sampler(struct lp_linear_sampler *samp);
|
||||
|
||||
|
||||
#define FAIL(s) do { \
|
||||
if (LP_DEBUG & DEBUG_LINEAR) \
|
||||
debug_printf("%s: %s\n", __FUNCTION__, s); \
|
||||
return FALSE; \
|
||||
} while (0)
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -50,6 +50,8 @@ lp_print_counters(void)
|
||||
|
||||
debug_printf("llvmpipe: nr_triangles: %9u\n", lp_count.nr_tris);
|
||||
debug_printf("llvmpipe: nr_culled_triangles: %9u\n", lp_count.nr_culled_tris);
|
||||
debug_printf("llvmpipe: nr_rectangles: %9u\n", lp_count.nr_rects);
|
||||
debug_printf("llvmpipe: nr_culled_rectangles: %9u\n", lp_count.nr_culled_rects);
|
||||
|
||||
total_64 = (lp_count.nr_empty_64 +
|
||||
lp_count.nr_fully_covered_64 +
|
||||
@@ -58,11 +60,14 @@ lp_print_counters(void)
|
||||
p1 = 100.0 * (float) lp_count.nr_empty_64 / (float) total_64;
|
||||
p2 = 100.0 * (float) lp_count.nr_fully_covered_64 / (float) total_64;
|
||||
p3 = 100.0 * (float) lp_count.nr_partially_covered_64 / (float) total_64;
|
||||
p4 = 100.0 * (float) lp_count.nr_blit_64 / (float) total_64;
|
||||
p5 = 100.0 * (float) lp_count.nr_shade_opaque_64 / (float) total_64;
|
||||
p6 = 100.0 * (float) lp_count.nr_shade_64 / (float) total_64;
|
||||
|
||||
debug_printf("llvmpipe: nr_64x64: %9u\n", total_64);
|
||||
debug_printf("llvmpipe: nr_fully_covered_64x64: %9u (%3.0f%% of %u)\n", lp_count.nr_fully_covered_64, p2, total_64);
|
||||
debug_printf("llvmpipe: nr_blit_64x64: %9u (%3.0f%% of %u)\n", lp_count.nr_blit_64, p4, total_64);
|
||||
debug_printf("llvmpipe: nr_pure_blit_64x64: %9u (%3.0f%% of %u)\n", lp_count.nr_pure_blit_64, 0.0, lp_count.nr_blit_64);
|
||||
debug_printf("llvmpipe: nr_shade_opaque_64x64: %9u (%3.0f%% of %u)\n", lp_count.nr_shade_opaque_64, p5, total_64);
|
||||
debug_printf("llvmpipe: nr_pure_shade_opaque: %9u (%3.0f%% of %u)\n", lp_count.nr_pure_shade_opaque_64, 0.0, lp_count.nr_shade_opaque_64);
|
||||
debug_printf("llvmpipe: nr_shade_64x64: %9u (%3.0f%% of %u)\n", lp_count.nr_shade_64, p6, total_64);
|
||||
@@ -98,6 +103,17 @@ lp_print_counters(void)
|
||||
debug_printf("llvmpipe: nr_empty_4x4: %9u (%3.0f%% of %u)\n", lp_count.nr_empty_4, p1, total_4);
|
||||
debug_printf("llvmpipe: nr_non_empty_4x4: %9u (%3.0f%% of %u)\n", lp_count.nr_non_empty_4, p4, total_4);
|
||||
|
||||
total_4 = (lp_count.nr_rect_partially_covered_4 +
|
||||
lp_count.nr_rect_fully_covered_4);
|
||||
|
||||
p1 = 100.0 * (float) lp_count.nr_rect_partially_covered_4 / (float) total_4;
|
||||
p2 = 100.0 * (float) lp_count.nr_rect_fully_covered_4 / (float) total_4;
|
||||
|
||||
debug_printf("llvmpipe: nr_rect_4x4: %9u\n", total_4);
|
||||
debug_printf("llvmpipe: nr_rect_full_4x4: %9u (%3.0f%% of %u)\n", lp_count.nr_rect_fully_covered_4, p1, total_4);
|
||||
debug_printf("llvmpipe: nr_rect_part_4x4: %9u (%3.0f%% of %u)\n", lp_count.nr_rect_partially_covered_4, p2, total_4);
|
||||
|
||||
|
||||
debug_printf("llvmpipe: nr_color_tile_clear: %9u\n", lp_count.nr_color_tile_clear);
|
||||
debug_printf("llvmpipe: nr_color_tile_load: %9u\n", lp_count.nr_color_tile_load);
|
||||
debug_printf("llvmpipe: nr_color_tile_store: %9u\n", lp_count.nr_color_tile_store);
|
||||
|
||||
@@ -42,9 +42,13 @@ struct lp_counters
|
||||
{
|
||||
unsigned nr_tris;
|
||||
unsigned nr_culled_tris;
|
||||
unsigned nr_rects;
|
||||
unsigned nr_culled_rects;
|
||||
unsigned nr_empty_64;
|
||||
unsigned nr_fully_covered_64;
|
||||
unsigned nr_partially_covered_64;
|
||||
unsigned nr_blit_64;
|
||||
unsigned nr_pure_blit_64;
|
||||
unsigned nr_pure_shade_opaque_64;
|
||||
unsigned nr_pure_shade_64;
|
||||
unsigned nr_shade_64;
|
||||
@@ -55,6 +59,8 @@ struct lp_counters
|
||||
unsigned nr_empty_4;
|
||||
unsigned nr_fully_covered_4;
|
||||
unsigned nr_partially_covered_4;
|
||||
unsigned nr_rect_fully_covered_4;
|
||||
unsigned nr_rect_partially_covered_4;
|
||||
unsigned nr_non_empty_4;
|
||||
unsigned nr_llvm_compiles;
|
||||
int64_t llvm_compile_time; /**< total, in microseconds */
|
||||
|
||||
@@ -508,6 +508,126 @@ lp_rast_shade_quads_mask(struct lp_rasterizer_task *task,
|
||||
lp_rast_shade_quads_mask_sample(task, inputs, x, y, new_mask);
|
||||
}
|
||||
|
||||
/**
|
||||
* Directly copy pixels from a texture to the destination color buffer.
|
||||
* This is a bin command called during bin processing.
|
||||
*/
|
||||
static void
|
||||
lp_rast_blit_tile_to_dest(struct lp_rasterizer_task *task,
|
||||
const union lp_rast_cmd_arg arg)
|
||||
{
|
||||
const struct lp_scene *scene = task->scene;
|
||||
const struct lp_rast_shader_inputs *inputs = arg.shade_tile;
|
||||
const struct lp_rast_state *state = task->state;
|
||||
struct lp_fragment_shader_variant *variant = state->variant;
|
||||
const struct lp_jit_texture *texture = &state->jit_context.textures[0];
|
||||
const uint8_t *src;
|
||||
uint8_t *dst;
|
||||
unsigned src_stride;
|
||||
unsigned dst_stride;
|
||||
struct pipe_surface *cbuf = scene->fb.cbufs[0];
|
||||
const unsigned face_slice = cbuf->u.tex.first_layer;
|
||||
const unsigned level = cbuf->u.tex.level;
|
||||
struct llvmpipe_resource *lpt = llvmpipe_resource(cbuf->texture);
|
||||
int src_x, src_y;
|
||||
|
||||
LP_DBG(DEBUG_RAST, "%s\n", __FUNCTION__);
|
||||
|
||||
if (inputs->disable) {
|
||||
/* This command was partially binned and has been disabled */
|
||||
return;
|
||||
}
|
||||
|
||||
dst = llvmpipe_get_texture_image_address(lpt, face_slice, level);
|
||||
|
||||
if (!dst)
|
||||
return;
|
||||
|
||||
dst_stride = lpt->row_stride[level];
|
||||
|
||||
src = texture->base;
|
||||
src_stride = texture->row_stride[0];
|
||||
|
||||
src_x = util_iround(GET_A0(inputs)[1][0]*texture->width - 0.5f);
|
||||
src_y = util_iround(GET_A0(inputs)[1][1]*texture->height - 0.5f);
|
||||
|
||||
src_x = src_x + task->x;
|
||||
src_y = src_y + task->y;
|
||||
|
||||
if (0) {
|
||||
union util_color uc;
|
||||
uc.ui[0] = 0xff0000ff;
|
||||
util_fill_rect(dst,
|
||||
cbuf->format,
|
||||
dst_stride,
|
||||
task->x,
|
||||
task->y,
|
||||
task->width,
|
||||
task->height,
|
||||
&uc);
|
||||
return;
|
||||
}
|
||||
|
||||
if (src_x >= 0 &&
|
||||
src_y >= 0 &&
|
||||
src_x + task->width <= texture->width &&
|
||||
src_y + task->height <= texture->height) {
|
||||
|
||||
if (variant->shader->kind == LP_FS_KIND_BLIT_RGBA ||
|
||||
(variant->shader->kind == LP_FS_KIND_BLIT_RGB1 &&
|
||||
cbuf->format == PIPE_FORMAT_B8G8R8X8_UNORM)) {
|
||||
util_copy_rect(dst,
|
||||
cbuf->format,
|
||||
dst_stride,
|
||||
task->x, task->y,
|
||||
task->width, task->height,
|
||||
src, src_stride,
|
||||
src_x, src_y);
|
||||
return;
|
||||
}
|
||||
|
||||
if (variant->shader->kind == LP_FS_KIND_BLIT_RGB1) {
|
||||
if (cbuf->format == PIPE_FORMAT_B8G8R8A8_UNORM) {
|
||||
int x, y;
|
||||
|
||||
dst += task->x * 4;
|
||||
src += src_x * 4;
|
||||
dst += task->y * dst_stride;
|
||||
src += src_y * src_stride;
|
||||
|
||||
for (y = 0; y < task->height; ++y) {
|
||||
const uint32_t *src_row = (const uint32_t *)src;
|
||||
uint32_t *dst_row = (uint32_t *)dst;
|
||||
|
||||
for (x = 0; x < task->width; ++x) {
|
||||
*dst_row++ = *src_row++ | 0xff000000;
|
||||
}
|
||||
dst += dst_stride;
|
||||
src += src_stride;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Fall back to the jit shaders.
|
||||
*/
|
||||
|
||||
lp_rast_shade_tile_opaque(task, arg);
|
||||
}
|
||||
|
||||
static void
|
||||
lp_rast_blit_tile(struct lp_rasterizer_task *task,
|
||||
const union lp_rast_cmd_arg arg)
|
||||
{
|
||||
/* This kindof just works, but isn't efficient:
|
||||
*/
|
||||
lp_rast_blit_tile_to_dest(task, arg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Begin a new occlusion query.
|
||||
* This is a bin command put in all bins.
|
||||
@@ -597,8 +717,123 @@ lp_rast_tile_end(struct lp_rasterizer_task *task)
|
||||
task->bin = NULL;
|
||||
}
|
||||
|
||||
static lp_rast_cmd_func dispatch[LP_RAST_OP_MAX] =
|
||||
{
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* Currently have two rendering paths only - the general case triangle
|
||||
* path and the super-specialized blit/clear path.
|
||||
*/
|
||||
#define TRI ((LP_RAST_FLAGS_TRI <<1)-1) /* general case */
|
||||
#define RECT ((LP_RAST_FLAGS_RECT<<1)-1) /* direct rectangle rasterizer */
|
||||
#define BLIT ((LP_RAST_FLAGS_BLIT<<1)-1) /* write direct-to-dest */
|
||||
|
||||
static const unsigned
|
||||
rast_flags[] = {
|
||||
BLIT, /* clear color */
|
||||
TRI, /* clear zstencil */
|
||||
TRI, /* triangle_1 */
|
||||
TRI, /* triangle_2 */
|
||||
TRI, /* triangle_3 */
|
||||
TRI, /* triangle_4 */
|
||||
TRI, /* triangle_5 */
|
||||
TRI, /* triangle_6 */
|
||||
TRI, /* triangle_7 */
|
||||
TRI, /* triangle_8 */
|
||||
TRI, /* triangle_3_4 */
|
||||
TRI, /* triangle_3_16 */
|
||||
TRI, /* triangle_4_16 */
|
||||
RECT, /* shade_tile */
|
||||
RECT, /* shade_tile_opaque */
|
||||
TRI, /* begin_query */
|
||||
TRI, /* end_query */
|
||||
BLIT, /* set_state, */
|
||||
TRI, /* lp_rast_triangle_32_1 */
|
||||
TRI, /* lp_rast_triangle_32_2 */
|
||||
TRI, /* lp_rast_triangle_32_3 */
|
||||
TRI, /* lp_rast_triangle_32_4 */
|
||||
TRI, /* lp_rast_triangle_32_5 */
|
||||
TRI, /* lp_rast_triangle_32_6 */
|
||||
TRI, /* lp_rast_triangle_32_7 */
|
||||
TRI, /* lp_rast_triangle_32_8 */
|
||||
TRI, /* lp_rast_triangle_32_3_4 */
|
||||
TRI, /* lp_rast_triangle_32_3_16 */
|
||||
TRI, /* lp_rast_triangle_32_4_16 */
|
||||
TRI, /* lp_rast_triangle_ms_1 */
|
||||
TRI, /* lp_rast_triangle_ms_2 */
|
||||
TRI, /* lp_rast_triangle_ms_3 */
|
||||
TRI, /* lp_rast_triangle_ms_4 */
|
||||
TRI, /* lp_rast_triangle_ms_5 */
|
||||
TRI, /* lp_rast_triangle_ms_6 */
|
||||
TRI, /* lp_rast_triangle_ms_7 */
|
||||
TRI, /* lp_rast_triangle_ms_8 */
|
||||
TRI, /* lp_rast_triangle_ms_3_4 */
|
||||
TRI, /* lp_rast_triangle_ms_3_16 */
|
||||
TRI, /* lp_rast_triangle_ms_4_16 */
|
||||
|
||||
RECT, /* rectangle */
|
||||
BLIT, /* blit */
|
||||
};
|
||||
|
||||
/*
|
||||
*/
|
||||
static const lp_rast_cmd_func
|
||||
dispatch_blit[] = {
|
||||
lp_rast_clear_color,
|
||||
NULL, /* clear_zstencil */
|
||||
NULL, /* triangle_1 */
|
||||
NULL, /* triangle_2 */
|
||||
NULL, /* triangle_3 */
|
||||
NULL, /* triangle_4 */
|
||||
NULL, /* triangle_5 */
|
||||
NULL, /* triangle_6 */
|
||||
NULL, /* triangle_7 */
|
||||
NULL, /* triangle_8 */
|
||||
NULL, /* triangle_3_4 */
|
||||
NULL, /* triangle_3_16 */
|
||||
NULL, /* triangle_4_16 */
|
||||
NULL, /* shade_tile */
|
||||
NULL, /* shade_tile_opaque */
|
||||
NULL, /* begin_query */
|
||||
NULL, /* end_query */
|
||||
lp_rast_set_state, /* set_state */
|
||||
NULL, /* lp_rast_triangle_32_1 */
|
||||
NULL, /* lp_rast_triangle_32_2 */
|
||||
NULL, /* lp_rast_triangle_32_3 */
|
||||
NULL, /* lp_rast_triangle_32_4 */
|
||||
NULL, /* lp_rast_triangle_32_5 */
|
||||
NULL, /* lp_rast_triangle_32_6 */
|
||||
NULL, /* lp_rast_triangle_32_7 */
|
||||
NULL, /* lp_rast_triangle_32_8 */
|
||||
NULL, /* lp_rast_triangle_32_3_4 */
|
||||
NULL, /* lp_rast_triangle_32_3_16 */
|
||||
NULL, /* lp_rast_triangle_32_4_16 */
|
||||
NULL, /* lp_rast_triangle_ms_1 */
|
||||
NULL, /* lp_rast_triangle_ms_2 */
|
||||
NULL, /* lp_rast_triangle_ms_3 */
|
||||
NULL, /* lp_rast_triangle_ms_4 */
|
||||
NULL, /* lp_rast_triangle_ms_5 */
|
||||
NULL, /* lp_rast_triangle_ms_6 */
|
||||
NULL, /* lp_rast_triangle_ms_7 */
|
||||
NULL, /* lp_rast_triangle_ms_8 */
|
||||
NULL, /* lp_rast_triangle_ms_3_4 */
|
||||
NULL, /* lp_rast_triangle_ms_3_16 */
|
||||
NULL, /* lp_rast_triangle_ms_4_16 */
|
||||
|
||||
NULL, /* rectangle */
|
||||
lp_rast_blit_tile_to_dest,
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* Triangle and general case rasterization: Use the SOA llvm shdaers,
|
||||
* an active swizzled tile for each color buf, etc. Don't blit/clear
|
||||
* directly to destination surface as we know there are swizzled
|
||||
* operations coming.
|
||||
*/
|
||||
static const lp_rast_cmd_func
|
||||
dispatch_tri[] = {
|
||||
lp_rast_clear_color,
|
||||
lp_rast_clear_zstencil,
|
||||
lp_rast_triangle_1,
|
||||
@@ -639,27 +874,133 @@ static lp_rast_cmd_func dispatch[LP_RAST_OP_MAX] =
|
||||
lp_rast_triangle_ms_3_4,
|
||||
lp_rast_triangle_ms_3_16,
|
||||
lp_rast_triangle_ms_4_16,
|
||||
lp_rast_rectangle,
|
||||
lp_rast_blit_tile,
|
||||
};
|
||||
|
||||
|
||||
/* Debug rasterization with most fastpaths disabled.
|
||||
*/
|
||||
static const lp_rast_cmd_func
|
||||
dispatch_tri_debug[] =
|
||||
{
|
||||
lp_rast_clear_color,
|
||||
lp_rast_clear_zstencil,
|
||||
lp_rast_triangle_1,
|
||||
lp_rast_triangle_2,
|
||||
lp_rast_triangle_3,
|
||||
lp_rast_triangle_4,
|
||||
lp_rast_triangle_5,
|
||||
lp_rast_triangle_6,
|
||||
lp_rast_triangle_7,
|
||||
lp_rast_triangle_8,
|
||||
lp_rast_triangle_3_4,
|
||||
lp_rast_triangle_3_16,
|
||||
lp_rast_triangle_4_16,
|
||||
lp_rast_shade_tile,
|
||||
lp_rast_shade_tile,
|
||||
lp_rast_begin_query,
|
||||
lp_rast_end_query,
|
||||
lp_rast_set_state,
|
||||
lp_rast_triangle_32_1,
|
||||
lp_rast_triangle_32_2,
|
||||
lp_rast_triangle_32_3,
|
||||
lp_rast_triangle_32_4,
|
||||
lp_rast_triangle_32_5,
|
||||
lp_rast_triangle_32_6,
|
||||
lp_rast_triangle_32_7,
|
||||
lp_rast_triangle_32_8,
|
||||
lp_rast_triangle_32_3_4,
|
||||
lp_rast_triangle_32_3_16,
|
||||
lp_rast_triangle_32_4_16,
|
||||
lp_rast_triangle_ms_1,
|
||||
lp_rast_triangle_ms_2,
|
||||
lp_rast_triangle_ms_3,
|
||||
lp_rast_triangle_ms_4,
|
||||
lp_rast_triangle_ms_5,
|
||||
lp_rast_triangle_ms_6,
|
||||
lp_rast_triangle_ms_7,
|
||||
lp_rast_triangle_ms_8,
|
||||
lp_rast_triangle_ms_3_4,
|
||||
lp_rast_triangle_ms_3_16,
|
||||
lp_rast_triangle_ms_4_16,
|
||||
|
||||
lp_rast_rectangle,
|
||||
lp_rast_shade_tile,
|
||||
};
|
||||
|
||||
struct lp_bin_info
|
||||
lp_characterize_bin(const struct cmd_bin *bin)
|
||||
{
|
||||
struct cmd_block *block;
|
||||
struct lp_bin_info info;
|
||||
unsigned andflags = ~0;
|
||||
unsigned k, j = 0;
|
||||
|
||||
STATIC_ASSERT(ARRAY_SIZE(rast_flags) == LP_RAST_OP_MAX);
|
||||
|
||||
for (block = bin->head; block; block = block->next) {
|
||||
for (k = 0; k < block->count; k++, j++) {
|
||||
andflags &= rast_flags[block->cmd[k]];
|
||||
}
|
||||
}
|
||||
|
||||
info.type = andflags;
|
||||
info.count = j;
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
do_rasterize_bin(struct lp_rasterizer_task *task,
|
||||
const struct cmd_bin *bin,
|
||||
int x, int y)
|
||||
blit_rasterize_bin(struct lp_rasterizer_task *task,
|
||||
const struct cmd_bin *bin)
|
||||
{
|
||||
const struct cmd_block *block;
|
||||
unsigned k;
|
||||
|
||||
if (0)
|
||||
lp_debug_bin(bin, x, y);
|
||||
STATIC_ASSERT(ARRAY_SIZE(dispatch_blit) == LP_RAST_OP_MAX);
|
||||
|
||||
if (0) debug_printf("%s\n", __FUNCTION__);
|
||||
for (block = bin->head; block; block = block->next) {
|
||||
for (k = 0; k < block->count; k++) {
|
||||
dispatch[block->cmd[k]]( task, block->arg[k] );
|
||||
dispatch_blit[block->cmd[k]]( task, block->arg[k] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
tri_rasterize_bin(struct lp_rasterizer_task *task,
|
||||
const struct cmd_bin *bin,
|
||||
int x, int y)
|
||||
{
|
||||
const struct cmd_block *block;
|
||||
unsigned k;
|
||||
|
||||
STATIC_ASSERT(ARRAY_SIZE(dispatch_tri) == LP_RAST_OP_MAX);
|
||||
|
||||
for (block = bin->head; block; block = block->next) {
|
||||
for (k = 0; k < block->count; k++) {
|
||||
dispatch_tri[block->cmd[k]]( task, block->arg[k] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
debug_rasterize_bin(struct lp_rasterizer_task *task,
|
||||
const struct cmd_bin *bin)
|
||||
{
|
||||
const struct cmd_block *block;
|
||||
unsigned k;
|
||||
|
||||
STATIC_ASSERT(ARRAY_SIZE(dispatch_tri_debug) == LP_RAST_OP_MAX);
|
||||
|
||||
for (block = bin->head; block; block = block->next) {
|
||||
for (k = 0; k < block->count; k++) {
|
||||
dispatch_tri_debug[block->cmd[k]]( task, block->arg[k] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@@ -672,9 +1013,20 @@ static void
|
||||
rasterize_bin(struct lp_rasterizer_task *task,
|
||||
const struct cmd_bin *bin, int x, int y )
|
||||
{
|
||||
struct lp_bin_info info = lp_characterize_bin(bin);
|
||||
|
||||
lp_rast_tile_begin( task, bin, x, y );
|
||||
|
||||
do_rasterize_bin(task, bin, x, y);
|
||||
if (LP_DEBUG & DEBUG_NO_FASTPATH)
|
||||
debug_rasterize_bin(task, bin);
|
||||
else if (info.type & LP_RAST_FLAGS_BLIT)
|
||||
blit_rasterize_bin(task, bin);
|
||||
else if (task->scene->permit_linear_rasterizer &&
|
||||
!(LP_PERF & PERF_NO_RAST_LINEAR) &&
|
||||
(info.type & LP_RAST_FLAGS_RECT))
|
||||
lp_linear_rasterize_bin(task, bin);
|
||||
else
|
||||
tri_rasterize_bin(task, bin, x, y);
|
||||
|
||||
lp_rast_tile_end(task);
|
||||
|
||||
@@ -682,7 +1034,9 @@ rasterize_bin(struct lp_rasterizer_task *task,
|
||||
/* Debug/Perf flags:
|
||||
*/
|
||||
if (bin->head->count == 1) {
|
||||
if (bin->head->cmd[0] == LP_RAST_OP_SHADE_TILE_OPAQUE)
|
||||
if (bin->head->cmd[0] == LP_RAST_OP_BLIT)
|
||||
LP_COUNT(nr_pure_blit_64);
|
||||
else if (bin->head->cmd[0] == LP_RAST_OP_SHADE_TILE_OPAQUE)
|
||||
LP_COUNT(nr_pure_shade_opaque_64);
|
||||
else if (bin->head->cmd[0] == LP_RAST_OP_SHADE_TILE)
|
||||
LP_COUNT(nr_pure_shade_64);
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
|
||||
#include "pipe/p_compiler.h"
|
||||
#include "util/u_pack_color.h"
|
||||
#include "util/u_rect.h"
|
||||
#include "lp_jit.h"
|
||||
|
||||
|
||||
@@ -92,6 +93,15 @@ struct lp_rast_state {
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Texture blit offsets.
|
||||
*/
|
||||
struct lp_rast_blit {
|
||||
int16_t x0;
|
||||
int16_t y0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Coefficients necessary to run the shader at a given location.
|
||||
* First coefficient is position.
|
||||
@@ -101,7 +111,8 @@ struct lp_rast_shader_inputs {
|
||||
unsigned frontfacing:1; /** True for front-facing */
|
||||
unsigned disable:1; /** Partially binned, disable this command */
|
||||
unsigned opaque:1; /** Is opaque */
|
||||
unsigned pad0:13; /* wasted space */
|
||||
unsigned is_blit:1; /* blit */
|
||||
unsigned pad0:12; /* wasted space */
|
||||
unsigned view_index:16;
|
||||
unsigned stride; /* how much to advance data between a0, dadx, dady */
|
||||
unsigned layer; /* the layer to render to (from gs, already clamped) */
|
||||
@@ -146,6 +157,31 @@ struct lp_rast_triangle {
|
||||
};
|
||||
|
||||
|
||||
#define RECT_PLANE_LEFT 0x1
|
||||
#define RECT_PLANE_RIGHT 0x2
|
||||
#define RECT_PLANE_TOP 0x4
|
||||
#define RECT_PLANE_BOTTOM 0x8
|
||||
|
||||
/**
|
||||
* Rasterization information for a screen-aligned rectangle 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 lp_setup_context::data buffer.
|
||||
*/
|
||||
struct lp_rast_rectangle {
|
||||
#ifdef DEBUG
|
||||
float v[2][2]; /**< diagonal corners */
|
||||
#endif
|
||||
|
||||
/* Rectangle boundaries in integer pixels:
|
||||
*/
|
||||
struct u_rect box;
|
||||
|
||||
/* inputs for the shader */
|
||||
struct lp_rast_shader_inputs inputs;
|
||||
};
|
||||
|
||||
|
||||
struct lp_rast_clear_rb {
|
||||
union util_color color_val;
|
||||
unsigned cbuf;
|
||||
@@ -179,6 +215,7 @@ union lp_rast_cmd_arg {
|
||||
const struct lp_rast_triangle *tri;
|
||||
unsigned plane_mask;
|
||||
} triangle;
|
||||
const struct lp_rast_rectangle *rectangle;
|
||||
const struct lp_rast_state *set_state;
|
||||
const struct lp_rast_clear_rb *clear_rb;
|
||||
struct {
|
||||
@@ -227,6 +264,14 @@ lp_rast_arg_triangle_contained( const struct lp_rast_triangle *triangle,
|
||||
return arg;
|
||||
}
|
||||
|
||||
static inline union lp_rast_cmd_arg
|
||||
lp_rast_arg_rectangle( const struct lp_rast_rectangle *rectangle )
|
||||
{
|
||||
union lp_rast_cmd_arg arg;
|
||||
arg.rectangle = rectangle;
|
||||
return arg;
|
||||
}
|
||||
|
||||
static inline union lp_rast_cmd_arg
|
||||
lp_rast_arg_state( const struct lp_rast_state *state )
|
||||
{
|
||||
@@ -317,9 +362,27 @@ lp_rast_arg_null( void )
|
||||
#define LP_RAST_OP_MS_TRIANGLE_3_4 0x25
|
||||
#define LP_RAST_OP_MS_TRIANGLE_3_16 0x26
|
||||
#define LP_RAST_OP_MS_TRIANGLE_4_16 0x27
|
||||
#define LP_RAST_OP_MAX 0x28
|
||||
#define LP_RAST_OP_RECTANGLE 0x28 /* Keep at end */
|
||||
#define LP_RAST_OP_BLIT 0x29 /* Keep at end */
|
||||
|
||||
#define LP_RAST_OP_MAX 0x2a
|
||||
#define LP_RAST_OP_MASK 0xff
|
||||
|
||||
/* Returned by characterize_bin:
|
||||
*/
|
||||
#define LP_RAST_FLAGS_TRI (0x1)
|
||||
#define LP_RAST_FLAGS_RECT (0x2)
|
||||
#define LP_RAST_FLAGS_TILE (0x4)
|
||||
#define LP_RAST_FLAGS_BLIT (0x8)
|
||||
|
||||
struct lp_bin_info {
|
||||
unsigned type:8;
|
||||
unsigned count:24;
|
||||
};
|
||||
|
||||
struct lp_bin_info
|
||||
lp_characterize_bin(const struct cmd_bin *bin);
|
||||
|
||||
void
|
||||
lp_debug_bins( struct lp_scene *scene );
|
||||
void
|
||||
|
||||
@@ -23,7 +23,7 @@ static char get_label( int i )
|
||||
|
||||
|
||||
|
||||
static const char *cmd_names[LP_RAST_OP_MAX] =
|
||||
static const char *cmd_names[] =
|
||||
{
|
||||
"clear_color",
|
||||
"clear_zstencil",
|
||||
@@ -54,10 +54,24 @@ static const char *cmd_names[LP_RAST_OP_MAX] =
|
||||
"triangle_32_3_4",
|
||||
"triangle_32_3_16",
|
||||
"triangle_32_4_16",
|
||||
"lp_rast_triangle_ms_1",
|
||||
"lp_rast_triangle_ms_2",
|
||||
"lp_rast_triangle_ms_3",
|
||||
"lp_rast_triangle_ms_4",
|
||||
"lp_rast_triangle_ms_5",
|
||||
"lp_rast_triangle_ms_6",
|
||||
"lp_rast_triangle_ms_7",
|
||||
"lp_rast_triangle_ms_8",
|
||||
"lp_rast_triangle_ms_3_4",
|
||||
"lp_rast_triangle_ms_3_16",
|
||||
"lp_rast_triangle_ms_4_16",
|
||||
"rectangle",
|
||||
"blit_tile",
|
||||
};
|
||||
|
||||
static const char *cmd_name(unsigned cmd)
|
||||
{
|
||||
STATIC_ASSERT(ARRAY_SIZE(cmd_names) == LP_RAST_OP_MAX);
|
||||
assert(ARRAY_SIZE(cmd_names) > cmd);
|
||||
return cmd_names[cmd];
|
||||
}
|
||||
@@ -78,7 +92,9 @@ get_variant( const struct lp_rast_state *state,
|
||||
block->cmd[k] == LP_RAST_OP_TRIANGLE_4 ||
|
||||
block->cmd[k] == LP_RAST_OP_TRIANGLE_5 ||
|
||||
block->cmd[k] == LP_RAST_OP_TRIANGLE_6 ||
|
||||
block->cmd[k] == LP_RAST_OP_TRIANGLE_7)
|
||||
block->cmd[k] == LP_RAST_OP_TRIANGLE_7 ||
|
||||
block->cmd[k] == LP_RAST_OP_RECTANGLE ||
|
||||
block->cmd[k] == LP_RAST_OP_BLIT)
|
||||
return state->variant;
|
||||
|
||||
return NULL;
|
||||
@@ -98,6 +114,39 @@ is_blend( const struct lp_rast_state *state,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static boolean
|
||||
is_linear( const struct lp_rast_state *state,
|
||||
const struct cmd_block *block,
|
||||
int k )
|
||||
{
|
||||
if (block->cmd[k] == LP_RAST_OP_BLIT)
|
||||
return state->variant->jit_linear_blit != NULL;
|
||||
|
||||
if (block->cmd[k] == LP_RAST_OP_SHADE_TILE ||
|
||||
block->cmd[k] == LP_RAST_OP_SHADE_TILE_OPAQUE)
|
||||
return state->variant->jit_linear != NULL;
|
||||
|
||||
if (block->cmd[k] == LP_RAST_OP_RECTANGLE)
|
||||
return state->variant->jit_linear != NULL;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
static const char *
|
||||
get_fs_kind( const struct lp_rast_state *state,
|
||||
const struct cmd_block *block,
|
||||
int k )
|
||||
{
|
||||
const struct lp_fragment_shader_variant *variant = get_variant(state, block, k);
|
||||
|
||||
if (variant)
|
||||
return lp_debug_fs_kind(variant->shader->kind);
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static void
|
||||
@@ -105,9 +154,25 @@ debug_bin( const struct cmd_bin *bin, int x, int y )
|
||||
{
|
||||
const struct lp_rast_state *state = NULL;
|
||||
const struct cmd_block *head = bin->head;
|
||||
const char *type;
|
||||
struct lp_bin_info info;
|
||||
int i, j = 0;
|
||||
|
||||
debug_printf("bin %d,%d:\n", x, y);
|
||||
info = lp_characterize_bin(bin);
|
||||
|
||||
if (info.type & LP_RAST_FLAGS_BLIT)
|
||||
type = "blit";
|
||||
else if (info.type & LP_RAST_FLAGS_TILE)
|
||||
type = "tile";
|
||||
else if (info.type & LP_RAST_FLAGS_RECT)
|
||||
type = "rect";
|
||||
else if (info.type & LP_RAST_FLAGS_TRI)
|
||||
type = "tri";
|
||||
else
|
||||
type = "unknown";
|
||||
|
||||
|
||||
debug_printf("bin %d,%d: type %s\n", x, y, type);
|
||||
|
||||
while (head) {
|
||||
for (i = 0; i < head->count; i++, j++) {
|
||||
@@ -138,7 +203,64 @@ static void plot(struct tile *tile,
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Scan the tile in chunks and figure out which pixels to rasterize
|
||||
* for this rectangle.
|
||||
*/
|
||||
static int
|
||||
debug_rectangle(int x, int y,
|
||||
const union lp_rast_cmd_arg arg,
|
||||
struct tile *tile,
|
||||
char val)
|
||||
{
|
||||
const struct lp_rast_rectangle *rect = arg.rectangle;
|
||||
boolean blend = tile->state->variant->key.blend.rt[0].blend_enable;
|
||||
unsigned i,j, count = 0;
|
||||
|
||||
/* Check for "disabled" rectangles generated in out-of-memory
|
||||
* conditions.
|
||||
*/
|
||||
if (rect->inputs.disable) {
|
||||
/* This command was partially binned and has been disabled */
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < TILE_SIZE; i++)
|
||||
{
|
||||
for (j = 0; j < TILE_SIZE; j++)
|
||||
{
|
||||
if (rect->box.x0 <= x + i &&
|
||||
rect->box.x1 >= x + i &&
|
||||
rect->box.y0 <= y + j &&
|
||||
rect->box.y1 >= y + j)
|
||||
{
|
||||
plot(tile, i, j, val, blend);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
debug_blit_tile(int x, int y,
|
||||
const union lp_rast_cmd_arg arg,
|
||||
struct tile *tile,
|
||||
char val)
|
||||
{
|
||||
const struct lp_rast_shader_inputs *inputs = arg.shade_tile;
|
||||
unsigned i,j;
|
||||
|
||||
if (inputs->disable)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < TILE_SIZE; i++)
|
||||
for (j = 0; j < TILE_SIZE; j++)
|
||||
plot(tile, i, j, val, FALSE);
|
||||
|
||||
return TILE_SIZE * TILE_SIZE;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
@@ -259,6 +381,8 @@ do_debug_bin( struct tile *tile,
|
||||
for (block = bin->head; block; block = block->next) {
|
||||
for (k = 0; k < block->count; k++, j++) {
|
||||
boolean blend = is_blend(tile->state, block, k);
|
||||
boolean linear = is_linear(tile->state, block, k);
|
||||
const char *fskind = get_fs_kind(tile->state, block, k);
|
||||
char val = get_label(j);
|
||||
int count = 0;
|
||||
|
||||
@@ -272,6 +396,9 @@ do_debug_bin( struct tile *tile,
|
||||
block->cmd[k] == LP_RAST_OP_CLEAR_ZSTENCIL)
|
||||
count = debug_clear_tile(tx, ty, block->arg[k], tile, val);
|
||||
|
||||
if (block->cmd[k] == LP_RAST_OP_BLIT)
|
||||
count = debug_blit_tile(tx, ty, block->arg[k], tile, val);
|
||||
|
||||
if (block->cmd[k] == LP_RAST_OP_SHADE_TILE ||
|
||||
block->cmd[k] == LP_RAST_OP_SHADE_TILE_OPAQUE)
|
||||
count = debug_shade_tile(tx, ty, block->arg[k], tile, val);
|
||||
@@ -285,12 +412,20 @@ do_debug_bin( struct tile *tile,
|
||||
block->cmd[k] == LP_RAST_OP_TRIANGLE_7)
|
||||
count = debug_triangle(tx, ty, block->arg[k], tile, val);
|
||||
|
||||
if (block->cmd[k] == LP_RAST_OP_RECTANGLE)
|
||||
count = debug_rectangle(tx, ty, block->arg[k], tile, val);
|
||||
|
||||
if (print_cmds) {
|
||||
debug_printf(" % 5d", count);
|
||||
|
||||
debug_printf(" %20s", fskind);
|
||||
|
||||
if (blend)
|
||||
debug_printf(" blended");
|
||||
|
||||
if (linear)
|
||||
debug_printf(" linear");
|
||||
|
||||
debug_printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,263 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright 2009-2021 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_rect.h"
|
||||
#include "util/u_surface.h"
|
||||
#include "util/u_pack_color.h"
|
||||
|
||||
#include "lp_scene_queue.h"
|
||||
#include "lp_debug.h"
|
||||
#include "lp_fence.h"
|
||||
#include "lp_perf.h"
|
||||
#include "lp_query.h"
|
||||
#include "lp_rast.h"
|
||||
#include "lp_rast_priv.h"
|
||||
#include "lp_scene.h"
|
||||
|
||||
|
||||
static void
|
||||
lp_rast_linear_clear(struct lp_rasterizer_task *task,
|
||||
const union lp_rast_cmd_arg arg)
|
||||
{
|
||||
const struct lp_scene *scene = task->scene;
|
||||
union util_color uc;
|
||||
|
||||
LP_DBG(DEBUG_RAST, "%s\n", __FUNCTION__);
|
||||
|
||||
uc = arg.clear_rb->color_val;
|
||||
|
||||
util_fill_rect(scene->cbufs[0].map,
|
||||
PIPE_FORMAT_B8G8R8A8_UNORM,
|
||||
scene->cbufs[0].stride,
|
||||
task->x,
|
||||
task->y,
|
||||
task->width,
|
||||
task->height,
|
||||
&uc);
|
||||
}
|
||||
|
||||
/* Run the scanline version of the shader across the whole tile.
|
||||
*/
|
||||
static void
|
||||
lp_rast_linear_tile(struct lp_rasterizer_task *task,
|
||||
const union lp_rast_cmd_arg arg)
|
||||
{
|
||||
const struct lp_rast_shader_inputs *inputs = arg.shade_tile;
|
||||
const struct lp_rast_state *state;
|
||||
struct lp_fragment_shader_variant *variant;
|
||||
const struct lp_scene *scene = task->scene;
|
||||
|
||||
if (inputs->disable)
|
||||
return;
|
||||
|
||||
state = task->state;
|
||||
assert(state);
|
||||
if (!state) {
|
||||
return;
|
||||
}
|
||||
variant = state->variant;
|
||||
|
||||
if (variant->jit_linear_blit &&
|
||||
inputs->is_blit)
|
||||
{
|
||||
if (variant->jit_linear_blit(state,
|
||||
task->x,
|
||||
task->y,
|
||||
task->width,
|
||||
task->height,
|
||||
(const float (*)[4])GET_A0(inputs),
|
||||
(const float (*)[4])GET_DADX(inputs),
|
||||
(const float (*)[4])GET_DADY(inputs),
|
||||
scene->cbufs[0].map,
|
||||
scene->cbufs[0].stride))
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (variant->jit_linear) {
|
||||
if (variant->jit_linear(state,
|
||||
task->x,
|
||||
task->y,
|
||||
task->width,
|
||||
task->height,
|
||||
(const float (*)[4])GET_A0(inputs),
|
||||
(const float (*)[4])GET_DADX(inputs),
|
||||
(const float (*)[4])GET_DADY(inputs),
|
||||
scene->cbufs[0].map,
|
||||
scene->cbufs[0].stride))
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
struct u_rect box;
|
||||
box.x0 = task->x;
|
||||
box.x1 = task->x + task->width - 1;
|
||||
box.y0 = task->y;
|
||||
box.y1 = task->y + task->height - 1;
|
||||
lp_rast_linear_rect_fallback(task, inputs, &box);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Run the scanline version of the shader on a rectangle within the
|
||||
* tile.
|
||||
*/
|
||||
static void
|
||||
lp_rast_linear_rect(struct lp_rasterizer_task *task,
|
||||
const union lp_rast_cmd_arg arg)
|
||||
{
|
||||
const struct lp_scene *scene = task->scene;
|
||||
const struct lp_rast_rectangle *rect = arg.rectangle;
|
||||
const struct lp_rast_shader_inputs *inputs = &rect->inputs;
|
||||
const struct lp_rast_state *state = task->state;
|
||||
struct lp_fragment_shader_variant *variant = state->variant;
|
||||
struct u_rect box;
|
||||
int width, height;
|
||||
|
||||
if (inputs->disable)
|
||||
return;
|
||||
|
||||
box.x0 = task->x;
|
||||
box.y0 = task->y;
|
||||
box.x1 = task->x + task->width - 1;
|
||||
box.y1 = task->y + task->height - 1;
|
||||
|
||||
u_rect_find_intersection(&rect->box, &box);
|
||||
|
||||
width = box.x1 - box.x0 + 1;
|
||||
height = box.y1 - box.y0 + 1;
|
||||
|
||||
/* Note that blit primitives can end up in the non-full-tile path,
|
||||
* the binner currently doesn't try to classify sub-tile
|
||||
* primitives. Can detect them here though.
|
||||
*/
|
||||
if (variant->jit_linear_blit &&
|
||||
inputs->is_blit)
|
||||
{
|
||||
if (variant->jit_linear_blit(state,
|
||||
box.x0, box.y0,
|
||||
width, height,
|
||||
(const float (*)[4])GET_A0(inputs),
|
||||
(const float (*)[4])GET_DADX(inputs),
|
||||
(const float (*)[4])GET_DADY(inputs),
|
||||
scene->cbufs[0].map,
|
||||
scene->cbufs[0].stride))
|
||||
return;
|
||||
}
|
||||
|
||||
if (variant->jit_linear)
|
||||
{
|
||||
if (variant->jit_linear(state,
|
||||
box.x0, box.y0,
|
||||
width, height,
|
||||
(const float (*)[4])GET_A0(inputs),
|
||||
(const float (*)[4])GET_DADX(inputs),
|
||||
(const float (*)[4])GET_DADY(inputs),
|
||||
scene->cbufs[0].map,
|
||||
scene->cbufs[0].stride))
|
||||
return;
|
||||
}
|
||||
|
||||
lp_rast_linear_rect_fallback(task, inputs, &box);
|
||||
}
|
||||
|
||||
|
||||
static const lp_rast_cmd_func
|
||||
dispatch_linear[] = {
|
||||
lp_rast_linear_clear, /* clear_color */
|
||||
NULL, /* clear_zstencil */
|
||||
NULL, /* triangle_1 */
|
||||
NULL, /* triangle_2 */
|
||||
NULL, /* triangle_3 */
|
||||
NULL, /* triangle_4 */
|
||||
NULL, /* triangle_5 */
|
||||
NULL, /* triangle_6 */
|
||||
NULL, /* triangle_7 */
|
||||
NULL, /* triangle_8 */
|
||||
NULL, /* triangle_3_4 */
|
||||
NULL, /* triangle_3_16 */
|
||||
NULL, /* triangle_4_16 */
|
||||
lp_rast_linear_tile, /* shade_tile */
|
||||
lp_rast_linear_tile, /* shade_tile_opaque */
|
||||
NULL, /* begin_query */
|
||||
NULL, /* end_query */
|
||||
lp_rast_set_state, /* set_state */
|
||||
NULL, /* lp_rast_triangle_32_1 */
|
||||
NULL, /* lp_rast_triangle_32_2 */
|
||||
NULL, /* lp_rast_triangle_32_3 */
|
||||
NULL, /* lp_rast_triangle_32_4 */
|
||||
NULL, /* lp_rast_triangle_32_5 */
|
||||
NULL, /* lp_rast_triangle_32_6 */
|
||||
NULL, /* lp_rast_triangle_32_7 */
|
||||
NULL, /* lp_rast_triangle_32_8 */
|
||||
NULL, /* lp_rast_triangle_32_3_4 */
|
||||
NULL, /* lp_rast_triangle_32_3_16 */
|
||||
NULL, /* lp_rast_triangle_32_4_16 */
|
||||
|
||||
NULL, /* lp_rast_triangle_ms_1 */
|
||||
NULL, /* lp_rast_triangle_ms_2 */
|
||||
NULL, /* lp_rast_triangle_ms_3 */
|
||||
NULL, /* lp_rast_triangle_ms_4 */
|
||||
NULL, /* lp_rast_triangle_ms_5 */
|
||||
NULL, /* lp_rast_triangle_ms_6 */
|
||||
NULL, /* lp_rast_triangle_ms_7 */
|
||||
NULL, /* lp_rast_triangle_ms_8 */
|
||||
NULL, /* lp_rast_triangle_ms_3_4 */
|
||||
NULL, /* lp_rast_triangle_ms_3_16 */
|
||||
NULL, /* lp_rast_triangle_ms_4_16 */
|
||||
|
||||
lp_rast_linear_rect, /* rect */
|
||||
lp_rast_linear_tile, /* blit */
|
||||
};
|
||||
|
||||
/* Assumptions for this path:
|
||||
* - Single color buffer, PIPE_FORMAT_B8G8R8A8_UNORM
|
||||
* - No depth buffer
|
||||
* - All primitives in bins are rect, tile, blit or clear.
|
||||
* - All shaders have a linear variant.
|
||||
*/
|
||||
void
|
||||
lp_linear_rasterize_bin(struct lp_rasterizer_task *task,
|
||||
const struct cmd_bin *bin)
|
||||
{
|
||||
const struct cmd_block *block;
|
||||
unsigned k;
|
||||
|
||||
STATIC_ASSERT(ARRAY_SIZE(dispatch_linear) == LP_RAST_OP_MAX);
|
||||
|
||||
if (0) debug_printf("%s\n", __FUNCTION__);
|
||||
|
||||
for (block = bin->head; block; block = block->next) {
|
||||
for (k = 0; k < block->count; k++) {
|
||||
assert(dispatch_linear[block->cmd[k]]);
|
||||
dispatch_linear[block->cmd[k]]( task, block->arg[k] );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,303 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright 2007-2021 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 rectangles within a tile
|
||||
*/
|
||||
|
||||
#include <limits.h>
|
||||
#include "util/u_math.h"
|
||||
#include "lp_debug.h"
|
||||
#include "lp_perf.h"
|
||||
#include "lp_rast_priv.h"
|
||||
|
||||
|
||||
/* Our 16-pixel stamps are layed out as:
|
||||
*
|
||||
* 0 1 2 3
|
||||
* 4 5 6 7
|
||||
* 8 9 10 11
|
||||
* 12 13 14 15
|
||||
*
|
||||
* Define bitmasks for each row and column in this layout:
|
||||
*/
|
||||
#define COLUMN0 ((1<<0)|(1<<4)|(1<<8) |(1<<12))
|
||||
#define COLUMN1 ((1<<1)|(1<<5)|(1<<9) |(1<<13))
|
||||
#define COLUMN2 ((1<<2)|(1<<6)|(1<<10)|(1<<14))
|
||||
#define COLUMN3 ((1<<3)|(1<<7)|(1<<11)|(1<<15))
|
||||
|
||||
#define ROW0 ((1<<0) |(1<<1) |(1<<2) |(1<<3))
|
||||
#define ROW1 ((1<<4) |(1<<5) |(1<<6) |(1<<7))
|
||||
#define ROW2 ((1<<8) |(1<<9) |(1<<10)|(1<<11))
|
||||
#define ROW3 ((1<<12)|(1<<13)|(1<<14)|(1<<15))
|
||||
|
||||
#define STAMP_SIZE 4
|
||||
|
||||
static unsigned left_mask_tab[STAMP_SIZE] = {
|
||||
COLUMN0 | COLUMN1 | COLUMN2 | COLUMN3,
|
||||
COLUMN1 | COLUMN2 | COLUMN3,
|
||||
COLUMN2 | COLUMN3,
|
||||
COLUMN3,
|
||||
};
|
||||
|
||||
static unsigned right_mask_tab[STAMP_SIZE] = {
|
||||
COLUMN0,
|
||||
COLUMN0 | COLUMN1,
|
||||
COLUMN0 | COLUMN1 | COLUMN2,
|
||||
COLUMN0 | COLUMN1 | COLUMN2 | COLUMN3,
|
||||
};
|
||||
|
||||
static unsigned top_mask_tab[STAMP_SIZE] = {
|
||||
ROW0 | ROW1 | ROW2 | ROW3,
|
||||
ROW1 | ROW2 | ROW3,
|
||||
ROW2 | ROW3,
|
||||
ROW3,
|
||||
};
|
||||
|
||||
static unsigned bottom_mask_tab[STAMP_SIZE] = {
|
||||
ROW0,
|
||||
ROW0 | ROW1,
|
||||
ROW0 | ROW1 | ROW2,
|
||||
ROW0 | ROW1 | ROW2 | ROW3,
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Shade all pixels in a 4x4 block. The fragment code omits the
|
||||
* triangle in/out tests.
|
||||
* \param x, y location of 4x4 block in window coords
|
||||
*/
|
||||
static void
|
||||
shade_quads_all( struct lp_rasterizer_task *task,
|
||||
const struct lp_rast_shader_inputs *inputs,
|
||||
unsigned x, unsigned y )
|
||||
{
|
||||
const struct lp_scene *scene = task->scene;
|
||||
const struct lp_rast_state *state = task->state;
|
||||
struct lp_fragment_shader_variant *variant = state->variant;
|
||||
uint8_t *color = scene->cbufs[0].map;
|
||||
unsigned stride = scene->cbufs[0].stride;
|
||||
uint8_t *cbufs[1];
|
||||
unsigned strides[1];
|
||||
|
||||
color += x * 4;
|
||||
color += y * stride;
|
||||
cbufs[0] = color;
|
||||
strides[0] = stride;
|
||||
|
||||
assert(!variant->key.depth.enabled);
|
||||
|
||||
/* run shader on 4x4 block */
|
||||
BEGIN_JIT_CALL(state, task);
|
||||
variant->jit_function[RAST_WHOLE]( &state->jit_context,
|
||||
x, y,
|
||||
1,
|
||||
(const float (*)[4])GET_A0(inputs),
|
||||
(const float (*)[4])GET_DADX(inputs),
|
||||
(const float (*)[4])GET_DADY(inputs),
|
||||
cbufs,
|
||||
NULL,
|
||||
0xffff,
|
||||
&task->thread_data,
|
||||
strides, 0, 0, 0 );
|
||||
END_JIT_CALL();
|
||||
}
|
||||
|
||||
static void
|
||||
shade_quads_mask(struct lp_rasterizer_task *task,
|
||||
const struct lp_rast_shader_inputs *inputs,
|
||||
unsigned x, unsigned y,
|
||||
unsigned mask)
|
||||
{
|
||||
const struct lp_rast_state *state = task->state;
|
||||
struct lp_fragment_shader_variant *variant = state->variant;
|
||||
const struct lp_scene *scene = task->scene;
|
||||
uint8_t *color = scene->cbufs[0].map;
|
||||
unsigned stride = scene->cbufs[0].stride;
|
||||
uint8_t *cbufs[1];
|
||||
unsigned strides[1];
|
||||
|
||||
color += x * 4;
|
||||
color += y * stride;
|
||||
cbufs[0] = color;
|
||||
strides[0] = stride;
|
||||
|
||||
assert(!variant->key.depth.enabled);
|
||||
|
||||
/* 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,
|
||||
x, y,
|
||||
1,
|
||||
(const float (*)[4])GET_A0(inputs),
|
||||
(const float (*)[4])GET_DADX(inputs),
|
||||
(const float (*)[4])GET_DADY(inputs),
|
||||
cbufs,
|
||||
NULL,
|
||||
mask,
|
||||
&task->thread_data,
|
||||
strides, 0, 0, 0);
|
||||
END_JIT_CALL();
|
||||
}
|
||||
|
||||
/* Shade a 4x4 stamp completely within the rectangle.
|
||||
*/
|
||||
static inline void
|
||||
full(struct lp_rasterizer_task *task,
|
||||
const struct lp_rast_shader_inputs *inputs,
|
||||
unsigned ix, unsigned iy)
|
||||
{
|
||||
shade_quads_all(task,
|
||||
inputs,
|
||||
ix * STAMP_SIZE,
|
||||
iy * STAMP_SIZE);
|
||||
}
|
||||
|
||||
/* Shade a 4x4 stamp which may be partially outside the rectangle,
|
||||
* according to the mask parameter.
|
||||
*/
|
||||
static inline void
|
||||
partial(struct lp_rasterizer_task *task,
|
||||
const struct lp_rast_shader_inputs *inputs,
|
||||
unsigned ix, unsigned iy,
|
||||
unsigned mask)
|
||||
{
|
||||
/* Unfortunately we can end up generating full blocks on this path,
|
||||
* need to catch them.
|
||||
*/
|
||||
if (mask == 0xffff)
|
||||
full(task, inputs, ix, iy);
|
||||
else {
|
||||
assert(mask);
|
||||
shade_quads_mask(task,
|
||||
inputs,
|
||||
ix * STAMP_SIZE,
|
||||
iy * STAMP_SIZE,
|
||||
mask);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Run the full SoA shader.
|
||||
*/
|
||||
void
|
||||
lp_rast_linear_rect_fallback(struct lp_rasterizer_task *task,
|
||||
const struct lp_rast_shader_inputs *inputs,
|
||||
const struct u_rect *box)
|
||||
{
|
||||
unsigned ix0, ix1, iy0, iy1;
|
||||
unsigned left_mask;
|
||||
unsigned right_mask;
|
||||
unsigned top_mask;
|
||||
unsigned bottom_mask;
|
||||
unsigned i,j;
|
||||
|
||||
/* The interior of the rectangle (if there is one) will be
|
||||
* rasterized as full 4x4 stamps.
|
||||
*
|
||||
* At each edge of the rectangle, however, there will be a fringe
|
||||
* of partial blocks where the edge lands somewhere in the middle
|
||||
* of a 4x4-pixel stamp.
|
||||
*
|
||||
* For each edge, precalculate a mask of the pixels inside that
|
||||
* edge for the first 4x4-pixel stamp.
|
||||
*
|
||||
* Note that at the corners, and for narrow rectangles, an
|
||||
* individual stamp may have two or more edges active. We'll deal
|
||||
* with that below by combining these masks as appropriate.
|
||||
*/
|
||||
left_mask = left_mask_tab [box->x0 & (STAMP_SIZE - 1)];
|
||||
right_mask = right_mask_tab [box->x1 & (STAMP_SIZE - 1)];
|
||||
top_mask = top_mask_tab [box->y0 & (STAMP_SIZE - 1)];
|
||||
bottom_mask = bottom_mask_tab [box->y1 & (STAMP_SIZE - 1)];
|
||||
|
||||
ix0 = box->x0 / STAMP_SIZE;
|
||||
ix1 = box->x1 / STAMP_SIZE;
|
||||
iy0 = box->y0 / STAMP_SIZE;
|
||||
iy1 = box->y1 / STAMP_SIZE;
|
||||
|
||||
/* Various special cases.
|
||||
*/
|
||||
if (ix0 == ix1 && iy0 == iy1) {
|
||||
/* Rectangle is contained within a single 4x4-pixel stamp:
|
||||
*/
|
||||
partial(task, inputs, ix0, iy0,
|
||||
(left_mask & right_mask &
|
||||
top_mask & bottom_mask));
|
||||
}
|
||||
else if (ix0 == ix1) {
|
||||
/* Left and right edges fall on the same 4-pixel-wide column:
|
||||
*/
|
||||
unsigned mask = left_mask & right_mask;
|
||||
partial(task, inputs, ix0, iy0, mask & top_mask);
|
||||
for (i = iy0 + 1; i < iy1; i++)
|
||||
partial(task, inputs, ix0, i, mask);
|
||||
partial(task, inputs, ix0, iy1, mask & bottom_mask);
|
||||
}
|
||||
else if (iy0 == iy1) {
|
||||
/* Top and bottom edges fall on the same 4-pixel-wide row:
|
||||
*/
|
||||
unsigned mask = top_mask & bottom_mask;
|
||||
partial(task, inputs, ix0, iy0, mask & left_mask);
|
||||
for (i = ix0 + 1; i < ix1; i++)
|
||||
partial(task, inputs, i, iy0, mask);
|
||||
partial(task, inputs, ix1, iy0, mask & right_mask);
|
||||
}
|
||||
else {
|
||||
/* Each pair of edges falls in a separate 4-pixel-wide
|
||||
* row/column.
|
||||
*/
|
||||
partial(task, inputs, ix0, iy0, left_mask & top_mask);
|
||||
partial(task, inputs, ix0, iy1, left_mask & bottom_mask);
|
||||
partial(task, inputs, ix1, iy0, right_mask & top_mask);
|
||||
partial(task, inputs, ix1, iy1, right_mask & bottom_mask);
|
||||
|
||||
for (i = ix0 + 1; i < ix1; i++)
|
||||
partial(task, inputs, i, iy0, top_mask);
|
||||
|
||||
for (i = ix0 + 1; i < ix1; i++)
|
||||
partial(task, inputs, i, iy1, bottom_mask);
|
||||
|
||||
for (i = iy0 + 1; i < iy1; i++)
|
||||
partial(task, inputs, ix0, i, left_mask);
|
||||
|
||||
for (i = iy0 + 1; i < iy1; i++)
|
||||
partial(task, inputs, ix1, i, right_mask);
|
||||
|
||||
/* Full interior blocks
|
||||
*/
|
||||
for (j = iy0 + 1; j < iy1; j++) {
|
||||
for (i = ix0 + 1; i < ix1; i++) {
|
||||
full(task, inputs, i, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -176,6 +176,7 @@ lp_rast_get_color_block_pointer(struct lp_rasterizer_task *task,
|
||||
color = task->color_tiles[buf] + pixel_offset;
|
||||
|
||||
if (layer) {
|
||||
assert(layer <= task->scene->fb_max_layer);
|
||||
color += layer * task->scene->cbufs[buf].layer_stride;
|
||||
}
|
||||
|
||||
@@ -347,6 +348,10 @@ void lp_rast_triangle_32_3_16( struct lp_rasterizer_task *,
|
||||
void lp_rast_triangle_32_4_16( struct lp_rasterizer_task *,
|
||||
const union lp_rast_cmd_arg );
|
||||
|
||||
|
||||
void lp_rast_rectangle( struct lp_rasterizer_task *,
|
||||
const union lp_rast_cmd_arg );
|
||||
|
||||
void lp_rast_triangle_ms_1( struct lp_rasterizer_task *,
|
||||
const union lp_rast_cmd_arg );
|
||||
void lp_rast_triangle_ms_2( struct lp_rasterizer_task *,
|
||||
@@ -406,4 +411,13 @@ lp_rast_set_state(struct lp_rasterizer_task *task,
|
||||
void
|
||||
lp_debug_bin( const struct cmd_bin *bin, int x, int y );
|
||||
|
||||
void
|
||||
lp_linear_rasterize_bin(struct lp_rasterizer_task *task,
|
||||
const struct cmd_bin *bin);
|
||||
|
||||
void
|
||||
lp_rast_linear_rect_fallback(struct lp_rasterizer_task *task,
|
||||
const struct lp_rast_shader_inputs *inputs,
|
||||
const struct u_rect *box);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,255 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright 2007-2021 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 rectangles within a tile
|
||||
*/
|
||||
|
||||
#include <limits.h>
|
||||
#include "util/u_math.h"
|
||||
#include "lp_debug.h"
|
||||
#include "lp_perf.h"
|
||||
#include "lp_rast_priv.h"
|
||||
|
||||
/* Our 16-pixel stamps are layed out as:
|
||||
*
|
||||
* 0 1 2 3
|
||||
* 4 5 6 7
|
||||
* 8 9 10 11
|
||||
* 12 13 14 15
|
||||
*
|
||||
* Define bitmasks for each row and column in this layout:
|
||||
*/
|
||||
#define COLUMN0 ((1<<0)|(1<<4)|(1<<8) |(1<<12))
|
||||
#define COLUMN1 ((1<<1)|(1<<5)|(1<<9) |(1<<13))
|
||||
#define COLUMN2 ((1<<2)|(1<<6)|(1<<10)|(1<<14))
|
||||
#define COLUMN3 ((1<<3)|(1<<7)|(1<<11)|(1<<15))
|
||||
|
||||
#define ROW0 ((1<<0) |(1<<1) |(1<<2) |(1<<3))
|
||||
#define ROW1 ((1<<4) |(1<<5) |(1<<6) |(1<<7))
|
||||
#define ROW2 ((1<<8) |(1<<9) |(1<<10)|(1<<11))
|
||||
#define ROW3 ((1<<12)|(1<<13)|(1<<14)|(1<<15))
|
||||
|
||||
#define STAMP_SIZE 4
|
||||
|
||||
static unsigned left_mask_tab[STAMP_SIZE] = {
|
||||
COLUMN0 | COLUMN1 | COLUMN2 | COLUMN3,
|
||||
COLUMN1 | COLUMN2 | COLUMN3,
|
||||
COLUMN2 | COLUMN3,
|
||||
COLUMN3,
|
||||
};
|
||||
|
||||
static unsigned right_mask_tab[STAMP_SIZE] = {
|
||||
COLUMN0,
|
||||
COLUMN0 | COLUMN1,
|
||||
COLUMN0 | COLUMN1 | COLUMN2,
|
||||
COLUMN0 | COLUMN1 | COLUMN2 | COLUMN3,
|
||||
};
|
||||
|
||||
static unsigned top_mask_tab[STAMP_SIZE] = {
|
||||
ROW0 | ROW1 | ROW2 | ROW3,
|
||||
ROW1 | ROW2 | ROW3,
|
||||
ROW2 | ROW3,
|
||||
ROW3,
|
||||
};
|
||||
|
||||
static unsigned bottom_mask_tab[STAMP_SIZE] = {
|
||||
ROW0,
|
||||
ROW0 | ROW1,
|
||||
ROW0 | ROW1 | ROW2,
|
||||
ROW0 | ROW1 | ROW2 | ROW3,
|
||||
};
|
||||
|
||||
static inline void
|
||||
full(struct lp_rasterizer_task *task,
|
||||
const struct lp_rast_rectangle *rect,
|
||||
unsigned ix, unsigned iy)
|
||||
{
|
||||
LP_COUNT(nr_rect_fully_covered_4);
|
||||
lp_rast_shade_quads_all(task,
|
||||
&rect->inputs,
|
||||
task->x + ix * STAMP_SIZE,
|
||||
task->y + iy * STAMP_SIZE);
|
||||
}
|
||||
|
||||
static inline void
|
||||
partial(struct lp_rasterizer_task *task,
|
||||
const struct lp_rast_rectangle *rect,
|
||||
unsigned ix, unsigned iy,
|
||||
unsigned mask)
|
||||
{
|
||||
/* Unfortunately we can end up generating full blocks on this path,
|
||||
* need to catch them.
|
||||
*/
|
||||
if (mask == 0xffff)
|
||||
full(task, rect, ix, iy);
|
||||
else {
|
||||
assert(mask);
|
||||
LP_COUNT(nr_rect_partially_covered_4);
|
||||
lp_rast_shade_quads_mask(task,
|
||||
&rect->inputs,
|
||||
task->x + ix * STAMP_SIZE,
|
||||
task->y + iy * STAMP_SIZE,
|
||||
mask);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static inline void
|
||||
intersect_rect_and_tile(struct lp_rasterizer_task *task,
|
||||
const struct lp_rast_rectangle *rect,
|
||||
struct u_rect *box)
|
||||
{
|
||||
box->x0 = task->x;
|
||||
box->y0 = task->y;
|
||||
box->x1 = task->x + TILE_SIZE - 1;
|
||||
box->y1 = task->y + TILE_SIZE - 1;
|
||||
|
||||
assert(u_rect_test_intersection(&rect->box, box));
|
||||
|
||||
u_rect_find_intersection(&rect->box, box);
|
||||
|
||||
box->x0 -= task->x;
|
||||
box->x1 -= task->x;
|
||||
box->y0 -= task->y;
|
||||
box->y1 -= task->y;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Scan the tile in chunks and figure out which pixels to rasterize
|
||||
* for this rectangle.
|
||||
*/
|
||||
void
|
||||
lp_rast_rectangle(struct lp_rasterizer_task *task,
|
||||
const union lp_rast_cmd_arg arg)
|
||||
{
|
||||
const struct lp_rast_rectangle *rect = arg.rectangle;
|
||||
|
||||
struct u_rect box;
|
||||
unsigned ix0, ix1, iy0, iy1;
|
||||
unsigned left_mask;
|
||||
unsigned right_mask;
|
||||
unsigned top_mask;
|
||||
unsigned bottom_mask;
|
||||
unsigned i,j;
|
||||
|
||||
/* Check for "disabled" rectangles generated in out-of-memory
|
||||
* conditions.
|
||||
*/
|
||||
if (rect->inputs.disable) {
|
||||
/* This command was partially binned and has been disabled */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Intersect the rectangle with this tile.
|
||||
*/
|
||||
intersect_rect_and_tile(task, rect, &box);
|
||||
|
||||
/* The interior of the rectangle (if there is one) will be
|
||||
* rasterized as full 4x4 stamps.
|
||||
*
|
||||
* At each edge of the rectangle, however, there will be a fringe
|
||||
* of partial blocks where the edge lands somewhere in the middle
|
||||
* of a 4-pixel stamp.
|
||||
*
|
||||
* For each edge, precalculate a mask of the pixels inside that
|
||||
* edge for the first 4-pixel stamp.
|
||||
*
|
||||
* Note that at the corners, and for narrow rectangles, an
|
||||
* individual stamp may have two or more edges active. We'll deal
|
||||
* with that below by combining these masks as appropriate.
|
||||
*/
|
||||
left_mask = left_mask_tab [box.x0 & (STAMP_SIZE - 1)];
|
||||
right_mask = right_mask_tab [box.x1 & (STAMP_SIZE - 1)];
|
||||
top_mask = top_mask_tab [box.y0 & (STAMP_SIZE - 1)];
|
||||
bottom_mask = bottom_mask_tab [box.y1 & (STAMP_SIZE - 1)];
|
||||
|
||||
ix0 = box.x0 / STAMP_SIZE;
|
||||
ix1 = box.x1 / STAMP_SIZE;
|
||||
iy0 = box.y0 / STAMP_SIZE;
|
||||
iy1 = box.y1 / STAMP_SIZE;
|
||||
|
||||
/* Various special cases.
|
||||
*/
|
||||
if (ix0 == ix1 && iy0 == iy1) {
|
||||
/* Rectangle is contained within a single 4x4 stamp:
|
||||
*/
|
||||
partial(task, rect, ix0, iy0,
|
||||
(left_mask & right_mask &
|
||||
top_mask & bottom_mask));
|
||||
}
|
||||
else if (ix0 == ix1) {
|
||||
/* Left and right edges fall on the same 4-pixel-wide column:
|
||||
*/
|
||||
unsigned mask = left_mask & right_mask;
|
||||
partial(task, rect, ix0, iy0, mask & top_mask);
|
||||
for (i = iy0 + 1; i < iy1; i++)
|
||||
partial(task, rect, ix0, i, mask);
|
||||
partial(task, rect, ix0, iy1, mask & bottom_mask);
|
||||
}
|
||||
else if (iy0 == iy1) {
|
||||
/* Top and bottom edges fall on the same 4-pixel-wide row:
|
||||
*/
|
||||
unsigned mask = top_mask & bottom_mask;
|
||||
partial(task, rect, ix0, iy0, mask & left_mask);
|
||||
for (i = ix0 + 1; i < ix1; i++)
|
||||
partial(task, rect, i, iy0, mask);
|
||||
partial(task, rect, ix1, iy0, mask & right_mask);
|
||||
}
|
||||
else {
|
||||
/* Each pair of edges falls in a separate 4-pixel-wide
|
||||
* row/column.
|
||||
*/
|
||||
partial(task, rect, ix0, iy0, left_mask & top_mask);
|
||||
partial(task, rect, ix0, iy1, left_mask & bottom_mask);
|
||||
partial(task, rect, ix1, iy0, right_mask & top_mask);
|
||||
partial(task, rect, ix1, iy1, right_mask & bottom_mask);
|
||||
|
||||
for (i = ix0 + 1; i < ix1; i++)
|
||||
partial(task, rect, i, iy0, top_mask);
|
||||
|
||||
for (i = ix0 + 1; i < ix1; i++)
|
||||
partial(task, rect, i, iy1, bottom_mask);
|
||||
|
||||
for (i = iy0 + 1; i < iy1; i++)
|
||||
partial(task, rect, ix0, i, left_mask);
|
||||
|
||||
for (i = iy0 + 1; i < iy1; i++)
|
||||
partial(task, rect, ix1, i, right_mask);
|
||||
|
||||
/* Full interior blocks
|
||||
*/
|
||||
for (j = iy0 + 1; j < iy1; j++) {
|
||||
for (i = ix0 + 1; i < ix1; i++) {
|
||||
full(task, rect, i, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -261,6 +261,31 @@ sign_bits4(const __m128i *cstep, int cdiff)
|
||||
return _mm_movemask_epi8(result);
|
||||
}
|
||||
|
||||
#define COLUMN0 ((1<<0)|(1<<4)|(1<<8) |(1<<12))
|
||||
#define COLUMN1 ((1<<1)|(1<<5)|(1<<9) |(1<<13))
|
||||
#define COLUMN2 ((1<<2)|(1<<6)|(1<<10)|(1<<14))
|
||||
#define COLUMN3 ((1<<3)|(1<<7)|(1<<11)|(1<<15))
|
||||
|
||||
#define ROW0 ((1<<0) |(1<<1) |(1<<2) |(1<<3))
|
||||
#define ROW1 ((1<<4) |(1<<5) |(1<<6) |(1<<7))
|
||||
#define ROW2 ((1<<8) |(1<<9) |(1<<10)|(1<<11))
|
||||
#define ROW3 ((1<<12)|(1<<13)|(1<<14)|(1<<15))
|
||||
|
||||
#define STAMP_SIZE 4
|
||||
static unsigned bottom_mask_tab[STAMP_SIZE] = {
|
||||
ROW3,
|
||||
ROW3 | ROW2,
|
||||
ROW3 | ROW2 | ROW1,
|
||||
ROW3 | ROW2 | ROW1 | ROW0,
|
||||
};
|
||||
|
||||
static unsigned right_mask_tab[STAMP_SIZE] = {
|
||||
COLUMN3,
|
||||
COLUMN3 | COLUMN2,
|
||||
COLUMN3 | COLUMN2 | COLUMN1,
|
||||
COLUMN3 | COLUMN2 | COLUMN1 | COLUMN0,
|
||||
};
|
||||
|
||||
|
||||
#define NR_PLANES 3
|
||||
|
||||
|
||||
@@ -363,6 +363,16 @@ TRI_16(struct lp_rasterizer_task *task,
|
||||
|
||||
outmask = 0; /* outside one or more trivial reject planes */
|
||||
|
||||
if (x + 12 >= 64) {
|
||||
int i = ((x + 12) - 64) / 4;
|
||||
outmask |= right_mask_tab[i];
|
||||
}
|
||||
|
||||
if (y + 12 >= 64) {
|
||||
int i = ((y + 12) - 64) / 4;
|
||||
outmask |= bottom_mask_tab[i];
|
||||
}
|
||||
|
||||
x += task->x;
|
||||
y += task->y;
|
||||
|
||||
|
||||
@@ -68,9 +68,7 @@ lp_scene_create( struct pipe_context *pipe )
|
||||
return NULL;
|
||||
|
||||
scene->pipe = pipe;
|
||||
|
||||
scene->data.head =
|
||||
CALLOC_STRUCT(data_block);
|
||||
scene->data.head = &scene->data.first;
|
||||
|
||||
(void) mtx_init(&scene->mutex, mtx_plain);
|
||||
|
||||
@@ -101,8 +99,7 @@ lp_scene_destroy(struct lp_scene *scene)
|
||||
{
|
||||
lp_fence_reference(&scene->fence, NULL);
|
||||
mtx_destroy(&scene->mutex);
|
||||
assert(scene->data.head->next == NULL);
|
||||
FREE(scene->data.head);
|
||||
assert(scene->data.head == &scene->data.first);
|
||||
FREE(scene);
|
||||
}
|
||||
|
||||
@@ -129,8 +126,8 @@ lp_scene_is_empty(struct lp_scene *scene )
|
||||
|
||||
|
||||
/* Returns true if there has ever been a failed allocation attempt in
|
||||
* this scene. Used in triangle emit to avoid having to check success
|
||||
* at each bin.
|
||||
* this scene. Used in triangle/rectangle emit to avoid having to
|
||||
* check success at each bin.
|
||||
*/
|
||||
boolean
|
||||
lp_scene_is_oom(struct lp_scene *scene)
|
||||
@@ -222,7 +219,7 @@ lp_scene_begin_rasterization(struct lp_scene *scene)
|
||||
void
|
||||
lp_scene_end_rasterization(struct lp_scene *scene )
|
||||
{
|
||||
int i, j;
|
||||
int i;
|
||||
|
||||
/* Unmap color buffers */
|
||||
for (i = 0; i < scene->fb.nr_cbufs; i++) {
|
||||
@@ -248,19 +245,7 @@ lp_scene_end_rasterization(struct lp_scene *scene )
|
||||
|
||||
/* Reset all 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);
|
||||
bin->head = NULL;
|
||||
bin->tail = NULL;
|
||||
bin->last_state = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* If there are any bins which weren't cleared by the loop above,
|
||||
* they will be caught (on debug builds at least) by this assert:
|
||||
*/
|
||||
assert(lp_scene_is_empty(scene));
|
||||
memset(scene->tile, 0, sizeof scene->tile);
|
||||
|
||||
/* Decrement texture ref counts
|
||||
*/
|
||||
@@ -310,13 +295,14 @@ lp_scene_end_rasterization(struct lp_scene *scene )
|
||||
struct data_block_list *list = &scene->data;
|
||||
struct data_block *block, *tmp;
|
||||
|
||||
for (block = list->head->next; block; block = tmp) {
|
||||
for (block = list->head; block; block = tmp) {
|
||||
tmp = block->next;
|
||||
FREE(block);
|
||||
if (block != &list->first)
|
||||
FREE(block);
|
||||
}
|
||||
|
||||
list->head = &list->first;
|
||||
list->head->next = NULL;
|
||||
list->head->used = 0;
|
||||
}
|
||||
|
||||
lp_fence_reference(&scene->fence, NULL);
|
||||
|
||||
@@ -54,7 +54,8 @@ struct lp_rast_state;
|
||||
*/
|
||||
#define CMD_BLOCK_MAX 29
|
||||
|
||||
/* Bytes per data block.
|
||||
/* Bytes per data block. This effectively limits the maximum constant buffer
|
||||
* size.
|
||||
*/
|
||||
#define DATA_BLOCK_SIZE (64 * 1024)
|
||||
|
||||
@@ -181,6 +182,8 @@ struct lp_scene {
|
||||
unsigned resource_reference_size;
|
||||
|
||||
boolean alloc_failed;
|
||||
boolean permit_linear_rasterizer;
|
||||
|
||||
/**
|
||||
* Number of active tiles in each dimension.
|
||||
* This basically the framebuffer size divided by tile size
|
||||
@@ -236,7 +239,7 @@ lp_scene_alloc( struct lp_scene *scene, unsigned size)
|
||||
|
||||
if (LP_DEBUG & DEBUG_MEM)
|
||||
debug_printf("alloc %u block %u/%u tot %u/%u\n",
|
||||
size, block->used, DATA_BLOCK_SIZE,
|
||||
size, block->used, (unsigned)DATA_BLOCK_SIZE,
|
||||
scene->scene_size, LP_SCENE_MAX_SIZE);
|
||||
|
||||
if (block->used + size > DATA_BLOCK_SIZE) {
|
||||
@@ -270,7 +273,7 @@ lp_scene_alloc_aligned( struct lp_scene *scene, unsigned size,
|
||||
if (LP_DEBUG & DEBUG_MEM)
|
||||
debug_printf("alloc %u block %u/%u tot %u/%u\n",
|
||||
size + alignment - 1,
|
||||
block->used, DATA_BLOCK_SIZE,
|
||||
block->used, (unsigned)DATA_BLOCK_SIZE,
|
||||
scene->scene_size, LP_SCENE_MAX_SIZE);
|
||||
|
||||
if (block->used + size + alignment - 1 > DATA_BLOCK_SIZE) {
|
||||
@@ -288,17 +291,6 @@ lp_scene_alloc_aligned( struct lp_scene *scene, unsigned size,
|
||||
}
|
||||
|
||||
|
||||
/* 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->head && list->head->used >= size);
|
||||
list->head->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)
|
||||
|
||||
@@ -70,11 +70,15 @@ static const struct debug_named_value lp_debug_flags[] = {
|
||||
{ "counters", DEBUG_COUNTERS, NULL },
|
||||
{ "scene", DEBUG_SCENE, NULL },
|
||||
{ "fence", DEBUG_FENCE, NULL },
|
||||
{ "no_fastpath", DEBUG_NO_FASTPATH, NULL },
|
||||
{ "linear", DEBUG_LINEAR, NULL },
|
||||
{ "linear2", DEBUG_LINEAR2, NULL },
|
||||
{ "mem", DEBUG_MEM, NULL },
|
||||
{ "fs", DEBUG_FS, NULL },
|
||||
{ "cs", DEBUG_CS, NULL },
|
||||
{ "tgsi_ir", DEBUG_TGSI_IR, NULL },
|
||||
{ "cache_stats", DEBUG_CACHE_STATS, NULL },
|
||||
{ "accurate_a0", DEBUG_ACCURATE_A0 },
|
||||
DEBUG_NAMED_VALUE_END
|
||||
};
|
||||
#endif
|
||||
@@ -89,6 +93,8 @@ static const struct debug_named_value lp_perf_flags[] = {
|
||||
{ "no_blend", PERF_NO_BLEND, NULL },
|
||||
{ "no_depth", PERF_NO_DEPTH, NULL },
|
||||
{ "no_alphatest", PERF_NO_ALPHATEST, NULL },
|
||||
{ "no_rast_linear", PERF_NO_RAST_LINEAR, NULL },
|
||||
{ "no_shade", PERF_NO_SHADE, NULL },
|
||||
DEBUG_NAMED_VALUE_END
|
||||
};
|
||||
|
||||
@@ -1026,7 +1032,7 @@ llvmpipe_create_screen(struct sw_winsys *winsys)
|
||||
screen->use_tgsi = (LP_DEBUG & DEBUG_TGSI_IR);
|
||||
screen->num_threads = util_get_cpu_caps()->nr_cpus > 1 ? util_get_cpu_caps()->nr_cpus : 0;
|
||||
#ifdef EMBEDDED_DEVICE
|
||||
screen->num_threads = 0;
|
||||
screen->num_threads = MIN2(screen->num_threads, 2);
|
||||
#endif
|
||||
screen->num_threads = debug_get_num_option("LP_NUM_THREADS", screen->num_threads);
|
||||
screen->num_threads = MIN2(screen->num_threads, LP_MAX_THREADS);
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
#include "util/u_inlines.h"
|
||||
#include "util/u_memory.h"
|
||||
#include "util/u_pack_color.h"
|
||||
#include "util/u_cpu_detect.h"
|
||||
#include "util/u_viewport.h"
|
||||
#include "draw/draw_pipe.h"
|
||||
#include "util/os_time.h"
|
||||
@@ -53,6 +54,7 @@
|
||||
#include "lp_setup_context.h"
|
||||
#include "lp_screen.h"
|
||||
#include "lp_state.h"
|
||||
#include "lp_jit.h"
|
||||
#include "frontend/sw_winsys.h"
|
||||
|
||||
#include "draw/draw_context.h"
|
||||
@@ -84,6 +86,7 @@ lp_setup_get_empty_scene(struct lp_setup_context *setup)
|
||||
|
||||
lp_scene_begin_binning(setup->scene, &setup->fb);
|
||||
|
||||
setup->scene->permit_linear_rasterizer = setup->permit_linear_rasterizer;
|
||||
}
|
||||
|
||||
|
||||
@@ -98,6 +101,20 @@ first_triangle( struct lp_setup_context *setup,
|
||||
setup->triangle( setup, v0, v1, v2 );
|
||||
}
|
||||
|
||||
static boolean
|
||||
first_rectangle( struct lp_setup_context *setup,
|
||||
const float (*v0)[4],
|
||||
const float (*v1)[4],
|
||||
const float (*v2)[4],
|
||||
const float (*v3)[4],
|
||||
const float (*v4)[4],
|
||||
const float (*v5)[4])
|
||||
{
|
||||
assert(setup->state == SETUP_ACTIVE);
|
||||
lp_setup_choose_rect( setup );
|
||||
return setup->rect( setup, v0, v1, v2, v3, v4, v5 );
|
||||
}
|
||||
|
||||
static void
|
||||
first_line( struct lp_setup_context *setup,
|
||||
const float (*v0)[4],
|
||||
@@ -117,7 +134,8 @@ first_point( struct lp_setup_context *setup,
|
||||
setup->point( setup, v0 );
|
||||
}
|
||||
|
||||
void lp_setup_reset( struct lp_setup_context *setup )
|
||||
void
|
||||
lp_setup_reset( struct lp_setup_context *setup )
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
@@ -145,6 +163,7 @@ void lp_setup_reset( struct lp_setup_context *setup )
|
||||
setup->line = first_line;
|
||||
setup->point = first_point;
|
||||
setup->triangle = first_triangle;
|
||||
setup->rect = first_rectangle;
|
||||
}
|
||||
|
||||
|
||||
@@ -576,6 +595,7 @@ lp_setup_set_triangle_state( struct lp_setup_context *setup,
|
||||
setup->ccw_is_frontface = ccw_is_frontface;
|
||||
setup->cullmode = cull_mode;
|
||||
setup->triangle = first_triangle;
|
||||
setup->rect = first_rectangle;
|
||||
setup->multisample = multisample;
|
||||
setup->pixel_offset = half_pixel_center ? 0.5f : 0.0f;
|
||||
setup->bottom_edge_rule = bottom_edge_rule;
|
||||
@@ -600,6 +620,7 @@ lp_setup_set_line_state( struct lp_setup_context *setup,
|
||||
void
|
||||
lp_setup_set_point_state( struct lp_setup_context *setup,
|
||||
float point_size,
|
||||
boolean point_tri_clip,
|
||||
boolean point_size_per_vertex,
|
||||
uint sprite_coord_enable,
|
||||
uint sprite_coord_origin,
|
||||
@@ -610,6 +631,7 @@ lp_setup_set_point_state( struct lp_setup_context *setup,
|
||||
setup->point_size = point_size;
|
||||
setup->sprite_coord_enable = sprite_coord_enable;
|
||||
setup->sprite_coord_origin = sprite_coord_origin;
|
||||
setup->point_tri_clip = point_tri_clip;
|
||||
setup->point_size_per_vertex = point_size_per_vertex;
|
||||
setup->legacy_points = !point_quad_rasterization;
|
||||
}
|
||||
@@ -833,6 +855,7 @@ lp_setup_set_rasterizer_discard(struct lp_setup_context *setup,
|
||||
setup->line = first_line;
|
||||
setup->point = first_point;
|
||||
setup->triangle = first_triangle;
|
||||
setup->rect = first_rectangle;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -846,6 +869,24 @@ lp_setup_set_vertex_info(struct lp_setup_context *setup,
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lp_setup_set_linear_mode( struct lp_setup_context *setup,
|
||||
boolean mode )
|
||||
{
|
||||
/* The linear rasterizer requires sse2 both at compile and runtime,
|
||||
* in particular for the code in lp_rast_linear_fallback.c. This
|
||||
* is more than ten-year-old technology, so it's a reasonable
|
||||
* baseline.
|
||||
*/
|
||||
#if defined(PIPE_ARCH_SSE)
|
||||
setup->permit_linear_rasterizer = (mode &&
|
||||
util_get_cpu_caps()->has_sse2);
|
||||
#else
|
||||
setup->permit_linear_rasterizer = FALSE;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Called during state validation when LP_NEW_VIEWPORT is set.
|
||||
*/
|
||||
@@ -855,6 +896,7 @@ lp_setup_set_viewports(struct lp_setup_context *setup,
|
||||
const struct pipe_viewport_state *viewports)
|
||||
{
|
||||
struct llvmpipe_context *lp = llvmpipe_context(setup->pipe);
|
||||
float half_height, x0, y0;
|
||||
unsigned i;
|
||||
|
||||
LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__);
|
||||
@@ -862,6 +904,26 @@ lp_setup_set_viewports(struct lp_setup_context *setup,
|
||||
assert(num_viewports <= PIPE_MAX_VIEWPORTS);
|
||||
assert(viewports);
|
||||
|
||||
/*
|
||||
* Linear rasterizer path for scissor/viewport intersection.
|
||||
*
|
||||
* Calculate "scissor" rect from the (first) viewport.
|
||||
* Just like stored scissor rects need inclusive coords.
|
||||
* For rounding, assume half pixel center (d3d9 should not end up
|
||||
* with fractional viewports) - quite obviously for msaa we'd need
|
||||
* fractional values here (and elsewhere for the point bounding box).
|
||||
*
|
||||
* See: lp_setup.c::try_update_scene_state
|
||||
*/
|
||||
half_height = fabsf(viewports[0].scale[1]);
|
||||
x0 = viewports[0].translate[0] - viewports[0].scale[0];
|
||||
y0 = viewports[0].translate[1] - half_height;
|
||||
setup->vpwh.x0 = (int)(x0 + 0.5f);
|
||||
setup->vpwh.x1 = (int)(viewports[0].scale[0] * 2.0f + x0 - 0.5f);
|
||||
setup->vpwh.y0 = (int)(y0 + 0.5f);
|
||||
setup->vpwh.y1 = (int)(half_height * 2.0f + y0 - 0.5f);
|
||||
setup->dirty |= LP_SETUP_NEW_SCISSOR;
|
||||
|
||||
/*
|
||||
* For use in lp_state_fs.c, propagate the viewport values for all viewports.
|
||||
*/
|
||||
@@ -882,7 +944,7 @@ lp_setup_set_viewports(struct lp_setup_context *setup,
|
||||
|
||||
|
||||
/**
|
||||
* Called during state validation when LP_NEW_SAMPLER_VIEW is set.
|
||||
* Called directly by llvmpipe_set_sampler_views
|
||||
*/
|
||||
void
|
||||
lp_setup_set_fragment_sampler_views(struct lp_setup_context *setup,
|
||||
@@ -1032,7 +1094,6 @@ lp_setup_set_fragment_sampler_views(struct lp_setup_context *setup,
|
||||
setup->dirty |= LP_SETUP_NEW_FS;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Called during state validation when LP_NEW_SAMPLER is set.
|
||||
*/
|
||||
@@ -1066,6 +1127,8 @@ lp_setup_set_fragment_sampler_state(struct lp_setup_context *setup,
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Is the given texture referenced by any scene?
|
||||
* Note: we have to check all scenes including any scenes currently
|
||||
@@ -1320,6 +1383,8 @@ try_update_scene_state( struct lp_setup_context *setup )
|
||||
|
||||
if (setup->dirty & LP_SETUP_NEW_SCISSOR) {
|
||||
unsigned i;
|
||||
setup->scissor_or_vp_clip = setup->scissor_test;
|
||||
|
||||
for (i = 0; i < PIPE_MAX_VIEWPORTS; ++i) {
|
||||
setup->draw_regions[i] = setup->framebuffer;
|
||||
if (setup->scissor_test) {
|
||||
@@ -1327,6 +1392,36 @@ try_update_scene_state( struct lp_setup_context *setup )
|
||||
&setup->draw_regions[i]);
|
||||
}
|
||||
}
|
||||
if (setup->permit_linear_rasterizer) {
|
||||
/* NOTE: this only takes first vp into account. */
|
||||
boolean need_vp_scissoring = !!memcmp(&setup->vpwh, &setup->framebuffer,
|
||||
sizeof(setup->framebuffer));
|
||||
assert(setup->viewport_index_slot < 0);
|
||||
setup->scissor_or_vp_clip |= need_vp_scissoring;
|
||||
if (need_vp_scissoring) {
|
||||
u_rect_possible_intersection(&setup->vpwh,
|
||||
&setup->draw_regions[0]);
|
||||
}
|
||||
}
|
||||
else if (setup->point_tri_clip) {
|
||||
/*
|
||||
* for d3d-style point clipping, we're going to need
|
||||
* the fake vp scissor too. Hence do the intersection with vp,
|
||||
* but don't indicate this. As above this will only work for first vp
|
||||
* which should be ok because we instruct draw to only skip point
|
||||
* clipping when there's only one viewport (this works because d3d10
|
||||
* points are always single pixel).
|
||||
* (Also note that if we have permit_linear_rasterizer this will
|
||||
* cause large points to always get vp scissored, regardless the
|
||||
* point_tri_clip setting.)
|
||||
*/
|
||||
boolean need_vp_scissoring = !!memcmp(&setup->vpwh, &setup->framebuffer,
|
||||
sizeof(setup->framebuffer));
|
||||
if (need_vp_scissoring) {
|
||||
u_rect_possible_intersection(&setup->vpwh,
|
||||
&setup->draw_regions[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setup->dirty = 0;
|
||||
|
||||
@@ -88,7 +88,8 @@ lp_setup_set_line_state( struct lp_setup_context *setup,
|
||||
|
||||
void
|
||||
lp_setup_set_point_state( struct lp_setup_context *setup,
|
||||
float point_size,
|
||||
float point_size,
|
||||
boolean point_tri_clip,
|
||||
boolean point_size_per_vertex,
|
||||
uint sprite_coord_enable,
|
||||
uint sprite_coord_origin,
|
||||
@@ -168,6 +169,10 @@ void
|
||||
lp_setup_set_vertex_info( struct lp_setup_context *setup,
|
||||
struct vertex_info *info );
|
||||
|
||||
void
|
||||
lp_setup_set_linear_mode( struct lp_setup_context *setup,
|
||||
boolean permit_linear_rasterizer );
|
||||
|
||||
void
|
||||
lp_setup_begin_query(struct lp_setup_context *setup,
|
||||
struct llvmpipe_query *pq);
|
||||
|
||||
@@ -0,0 +1,398 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright 2010-2021 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.
|
||||
*
|
||||
**************************************************************************/
|
||||
|
||||
/**
|
||||
* Look for common topology patterns which can be converted into rectangles.
|
||||
*/
|
||||
|
||||
|
||||
#include "lp_setup_context.h"
|
||||
#include "draw/draw_vbuf.h"
|
||||
#include "draw/draw_vertex.h"
|
||||
#include "util/u_memory.h"
|
||||
#include "util/u_math.h"
|
||||
#include "lp_state_fs.h"
|
||||
#include "lp_state_setup.h"
|
||||
#include "lp_perf.h"
|
||||
|
||||
|
||||
/**
|
||||
* Duplicated from lp_setup_vbuf.c.
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
/* Aero sends these weird zero area triangles. Test for them here.
|
||||
*/
|
||||
static boolean
|
||||
is_zero_area(const float (*v0)[4],
|
||||
const float (*v1)[4],
|
||||
const float (*v2)[4])
|
||||
{
|
||||
/* Specialized test for v0.y == v1.y == v2.y.
|
||||
*/
|
||||
return (v0[0][1] == v1[0][1] &&
|
||||
v0[0][1] == v2[0][1]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Assuming axis-aligned stretch blit (s a function of x alone, t a
|
||||
* function of y alone), create a new vertex as in:
|
||||
*
|
||||
* vx------+
|
||||
* | |
|
||||
* | |
|
||||
* out-----vy
|
||||
*/
|
||||
static void
|
||||
make_vert(const float (*vx)[4],
|
||||
const float (*vy)[4],
|
||||
float (*out)[4])
|
||||
{
|
||||
out[0][0] = vx[0][0];
|
||||
out[0][1] = vy[0][1];
|
||||
out[0][2] = vx[0][2];
|
||||
out[0][3] = vx[0][3];
|
||||
out[1][0] = vx[1][0];
|
||||
out[1][1] = vy[1][1];
|
||||
}
|
||||
|
||||
|
||||
/* Calculate axis-aligned interpolant for s as a function of x.
|
||||
*/
|
||||
static void
|
||||
calc_interps(float x0, float x1,
|
||||
float s0, float s1,
|
||||
float *a, float *b)
|
||||
{
|
||||
assert(x0 != x1);
|
||||
*a = (s0 - s1) / (x0 - x1);
|
||||
*b = s0 - *a * x0;
|
||||
}
|
||||
|
||||
|
||||
/* Validate axis-aligned interpolant for s and t as functions of x and
|
||||
* y respectively.
|
||||
*/
|
||||
static boolean
|
||||
test_interps(const_float4_ptr v,
|
||||
float as, float bs,
|
||||
float at, float bt)
|
||||
{
|
||||
float s = as * v[0][0] + bs;
|
||||
float t = at * v[0][1] + bt;
|
||||
return (util_is_approx(s, v[1][0], 1/4096.0) &&
|
||||
util_is_approx(t, v[1][1], 1/4096.0));
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
rect(struct lp_setup_context *setup,
|
||||
const float (*v0)[4],
|
||||
const float (*v1)[4],
|
||||
const float (*v2)[4])
|
||||
{
|
||||
ASSERTED int culled = LP_COUNT_GET(nr_culled_rects);
|
||||
|
||||
if (0) {
|
||||
float as, bs, at, bt;
|
||||
calc_interps(v0[0][0], v2[0][0], v0[1][0], v2[1][0], &as, &bs);
|
||||
calc_interps(v0[0][1], v2[0][1], v0[1][1], v2[1][1], &at, &bt);
|
||||
assert(test_interps(v1, as, bs, at, bt));
|
||||
}
|
||||
|
||||
assert(v0[0][0] == v1[0][0]);
|
||||
assert(v1[0][1] == v2[0][1]);
|
||||
|
||||
lp_rect_cw(setup, v0, v1, v2, TRUE);
|
||||
|
||||
assert(culled == LP_COUNT_GET(nr_culled_rects));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check this is an axis-aligned rectangle as in:
|
||||
*
|
||||
* v3------v0
|
||||
* | |
|
||||
* | |
|
||||
* v2------v1
|
||||
*/
|
||||
static boolean
|
||||
test_rect(const_float4_ptr v0,
|
||||
const_float4_ptr v1,
|
||||
const_float4_ptr v2,
|
||||
const_float4_ptr v3)
|
||||
{
|
||||
if (v0[0][0] != v1[0][0] ||
|
||||
v1[0][1] != v2[0][1] ||
|
||||
v2[0][0] != v3[0][0] ||
|
||||
v3[0][1] != v0[0][1])
|
||||
return FALSE;
|
||||
|
||||
if (v0[0][3] != 1.0 ||
|
||||
v1[0][3] != 1.0 ||
|
||||
v2[0][3] != 1.0 ||
|
||||
v3[0][3] != 1.0)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Aero sends the following shape as
|
||||
*
|
||||
* 18 12
|
||||
* +-------------------------------------------------/----+
|
||||
* |\ /--------- /|
|
||||
* | \ /--------- / |
|
||||
* | \ /--------- / |
|
||||
* | \ /--------- / |
|
||||
* vA + +--------------------------------------------+ + vC
|
||||
* | | 9 6 | |
|
||||
* | /| |\ |
|
||||
* | || || |
|
||||
* | / | | \ |
|
||||
* | | | | | |
|
||||
* | | | 3 0 | \ |
|
||||
* vB + / +--------------------------------------------+ | + vD
|
||||
* | | / ---------/ \ | |
|
||||
* |/ / ---------/ \ \|
|
||||
* ||/ ---------/ \||
|
||||
* |/ ---------/ \|
|
||||
* +----/-------------------------------------------------+
|
||||
* 1 2
|
||||
*
|
||||
* and in the following decomposition:
|
||||
* (0, 1, 2)
|
||||
* (3, 0, 1),
|
||||
* (6, 0, 2),
|
||||
* (9, 3, 1),
|
||||
* (12, 2, 6),
|
||||
* (12, 6, 9),
|
||||
* (18, 1, 9),
|
||||
* (18, 9, 12),
|
||||
*
|
||||
* There's no straight-forward way to interpret the existing vertices
|
||||
* as rectangles. Instead we convert this into four axis-aligned
|
||||
* rectangles by introducing new vertices at vA, vB, vC and vD, and
|
||||
* then drawing rectangles.
|
||||
*/
|
||||
static boolean
|
||||
check_elts24(struct lp_setup_context *setup, const void *vb, int stride)
|
||||
{
|
||||
const int count = 24;
|
||||
const int uniq[8] = { 0, 1, 2, 3, 6, 9, 12, 18 };
|
||||
const int elts[24] = {
|
||||
0, 1, 2,
|
||||
3, 0, 1,
|
||||
6, 0, 2,
|
||||
9, 3, 1,
|
||||
12, 2, 6,
|
||||
12, 6, 9,
|
||||
18, 1, 9,
|
||||
18, 9, 12
|
||||
};
|
||||
const_float4_ptr v0 = get_vert(vb, stride, 0);
|
||||
const_float4_ptr v1 = get_vert(vb, stride, 1);
|
||||
const_float4_ptr v2 = get_vert(vb, stride, 2);
|
||||
const_float4_ptr v3 = get_vert(vb, stride, 3);
|
||||
const_float4_ptr v6 = get_vert(vb, stride, 6);
|
||||
const_float4_ptr v9 = get_vert(vb, stride, 9);
|
||||
const_float4_ptr v12 = get_vert(vb, stride, 12);
|
||||
const_float4_ptr v18 = get_vert(vb, stride, 18);
|
||||
|
||||
/* Could just calculate a set of interpolants and bin rectangle
|
||||
* commands for this triangle list directly. Instead, introduce
|
||||
* some new vertices and feed to the rectangle setup code:
|
||||
*/
|
||||
PIPE_ALIGN_VAR(16) float vA[2][4];
|
||||
PIPE_ALIGN_VAR(16) float vB[2][4];
|
||||
PIPE_ALIGN_VAR(16) float vC[2][4];
|
||||
PIPE_ALIGN_VAR(16) float vD[2][4];
|
||||
|
||||
float as, bs;
|
||||
float at, bt;
|
||||
int i;
|
||||
|
||||
if (stride != 32)
|
||||
return FALSE;
|
||||
|
||||
/* Check the shape is two rectangles:
|
||||
*/
|
||||
if (!test_rect(v12, v2, v1, v18))
|
||||
return FALSE;
|
||||
|
||||
if (!test_rect(v6, v0, v3, v9))
|
||||
return FALSE;
|
||||
|
||||
/* XXX: check one rect is inside the other?
|
||||
*/
|
||||
|
||||
/* Check our tesselation matches:
|
||||
*/
|
||||
for (i = 0; i < count; i++) {
|
||||
if (memcmp(get_vert(vb, i, stride),
|
||||
get_vert(vb, elts[i], stride),
|
||||
6 * sizeof(float)) != 0)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Test that this is a stretch blit, meaning we should be able to
|
||||
* introduce vertices at will.
|
||||
*/
|
||||
calc_interps(v0[0][0], v2[0][0], v0[1][0], v2[1][0], &as, &bs);
|
||||
calc_interps(v0[0][1], v2[0][1], v0[1][1], v2[1][1], &at, &bt);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(uniq); i++) {
|
||||
const_float4_ptr v = get_vert(vb, stride, i);
|
||||
if (!test_interps(v, as, bs, at, bt))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
make_vert(v18, v9, vA);
|
||||
make_vert(v18, v3, vB);
|
||||
make_vert(v12, v9, vC);
|
||||
make_vert(v12, v3, vD);
|
||||
|
||||
assert(test_interps((const_float4_ptr)vA, as, bs, at, bt));
|
||||
assert(test_interps((const_float4_ptr)vB, as, bs, at, bt));
|
||||
assert(test_interps((const_float4_ptr)vC, as, bs, at, bt));
|
||||
assert(test_interps((const_float4_ptr)vD, as, bs, at, bt));
|
||||
|
||||
rect(setup,
|
||||
(const_float4_ptr)v12,
|
||||
(const_float4_ptr)vC,
|
||||
(const_float4_ptr)vA);
|
||||
|
||||
rect(setup,
|
||||
(const_float4_ptr)v9,
|
||||
(const_float4_ptr)v3,
|
||||
(const_float4_ptr)vB);
|
||||
|
||||
rect(setup,
|
||||
(const_float4_ptr)vD,
|
||||
(const_float4_ptr)v2,
|
||||
(const_float4_ptr)v1);
|
||||
|
||||
rect(setup,
|
||||
(const_float4_ptr)vC,
|
||||
(const_float4_ptr)vD,
|
||||
(const_float4_ptr)v0);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
boolean
|
||||
lp_setup_analyse_triangles(struct lp_setup_context *setup,
|
||||
const void *vb,
|
||||
int stride,
|
||||
int nr)
|
||||
{
|
||||
int i;
|
||||
const boolean variant_blit = setup->fs.current.variant->blit;
|
||||
|
||||
if (0) {
|
||||
debug_printf("%s %d\n", __FUNCTION__, nr);
|
||||
|
||||
if (variant_blit) {
|
||||
debug_printf(" - blit variant\n");
|
||||
}
|
||||
|
||||
for (i = 0; i < nr; i += 3) {
|
||||
const_float4_ptr v0 = get_vert(vb, i, stride);
|
||||
const_float4_ptr v1 = get_vert(vb, i+1, stride);
|
||||
const_float4_ptr v2 = get_vert(vb, i+2, stride);
|
||||
lp_setup_print_triangle(setup, v0, v1, v2);
|
||||
}
|
||||
}
|
||||
|
||||
/* When drawing some window navigator bars, aero sends a mixed up
|
||||
* rectangle:
|
||||
*
|
||||
* - first triangle ccw
|
||||
* - second triangle cw
|
||||
* - third triangle zero area.
|
||||
*/
|
||||
if (nr == 9 &&
|
||||
is_zero_area(get_vert(vb, nr-1, stride),
|
||||
get_vert(vb, nr-2, stride),
|
||||
get_vert(vb, nr-3, stride)))
|
||||
{
|
||||
const float (*v0)[4] = get_vert(vb, 0, stride);
|
||||
const float (*v1)[4] = get_vert(vb, 1, stride);
|
||||
const float (*v2)[4] = get_vert(vb, 2, stride);
|
||||
const float (*v3)[4] = get_vert(vb, 3, stride);
|
||||
const float (*v4)[4] = get_vert(vb, 4, stride);
|
||||
const float (*v5)[4] = get_vert(vb, 5, stride);
|
||||
|
||||
/*
|
||||
* [ v0, v1, v2 ] [ v3, v4, v5 ]
|
||||
* [(X0, Y0), (X0, Y1), (X1, Y1)] [(X1, Y0), (X1, Y1), (X0, Y0)]
|
||||
*/
|
||||
if (v0[0][0] == v1[0][0] && v0[0][0] == v5[0][0] &&
|
||||
v2[0][0] == v3[0][0] && v2[0][0] == v4[0][0] &&
|
||||
v0[0][1] == v3[0][1] && v0[0][1] == v5[0][1] &&
|
||||
v1[0][1] == v2[0][1] && v1[0][1] == v4[0][1]) {
|
||||
|
||||
lp_rect_cw(setup, v0, v1, v2, TRUE);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* When highlighting (?) windows, aero sends a window border
|
||||
* comprised of non-rectangular triangles, but which as a whole can
|
||||
* be decomposed into rectangles.
|
||||
*
|
||||
* Again, with a zero-area trailing triangle.
|
||||
*
|
||||
* This requires introducing a couple of new vertices, which are
|
||||
* luckily easy to compute.
|
||||
*/
|
||||
if (nr == 27 &&
|
||||
variant_blit &&
|
||||
setup->setup.variant->key.inputs[0].src_index == 1 &&
|
||||
setup->setup.variant->key.inputs[0].usage_mask == 0x3 &&
|
||||
is_zero_area(get_vert(vb, nr-1, stride),
|
||||
get_vert(vb, nr-2, stride),
|
||||
get_vert(vb, nr-3, stride)) &&
|
||||
check_elts24(setup, vb, stride))
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
@@ -96,15 +96,18 @@ struct lp_setup_context
|
||||
struct llvmpipe_query *active_queries[LP_MAX_ACTIVE_BINNED_QUERIES];
|
||||
unsigned active_binned_queries;
|
||||
|
||||
boolean flatshade_first;
|
||||
boolean ccw_is_frontface;
|
||||
boolean scissor_test;
|
||||
boolean point_size_per_vertex;
|
||||
boolean legacy_points;
|
||||
boolean rasterizer_discard;
|
||||
boolean multisample;
|
||||
boolean rectangular_lines;
|
||||
unsigned cullmode;
|
||||
unsigned flatshade_first:1;
|
||||
unsigned ccw_is_frontface:1;
|
||||
unsigned scissor_test:1;
|
||||
unsigned scissor_or_vp_clip:1;
|
||||
unsigned point_tri_clip:1;
|
||||
unsigned point_size_per_vertex:1;
|
||||
unsigned legacy_points:1;
|
||||
unsigned rasterizer_discard:1;
|
||||
unsigned permit_linear_rasterizer:1;
|
||||
unsigned multisample:1;
|
||||
unsigned rectangular_lines:1;
|
||||
unsigned cullmode:2; /**< PIPE_FACE_x */
|
||||
unsigned bottom_edge_rule;
|
||||
float pixel_offset;
|
||||
float line_width;
|
||||
@@ -117,6 +120,7 @@ struct lp_setup_context
|
||||
struct pipe_framebuffer_state fb;
|
||||
struct u_rect framebuffer;
|
||||
struct u_rect scissors[PIPE_MAX_VIEWPORTS];
|
||||
struct u_rect vpwh;
|
||||
struct u_rect draw_regions[PIPE_MAX_VIEWPORTS]; /* intersection of fb & scissor */
|
||||
struct lp_jit_viewport viewports[PIPE_MAX_VIEWPORTS];
|
||||
|
||||
@@ -179,6 +183,15 @@ struct lp_setup_context
|
||||
const float (*v0)[4],
|
||||
const float (*v1)[4],
|
||||
const float (*v2)[4]);
|
||||
|
||||
boolean
|
||||
(*rect)( struct lp_setup_context *,
|
||||
const float (*v0)[4],
|
||||
const float (*v1)[4],
|
||||
const float (*v2)[4],
|
||||
const float (*v3)[4],
|
||||
const float (*v4)[4],
|
||||
const float (*v5)[4]);
|
||||
};
|
||||
|
||||
static inline void
|
||||
@@ -199,6 +212,7 @@ scissor_planes_needed(boolean scis_planes[4], const struct u_rect *bbox,
|
||||
void lp_setup_choose_triangle( struct lp_setup_context *setup );
|
||||
void lp_setup_choose_line( struct lp_setup_context *setup );
|
||||
void lp_setup_choose_point( struct lp_setup_context *setup );
|
||||
void lp_setup_choose_rect( struct lp_setup_context *setup );
|
||||
|
||||
void lp_setup_init_vbuf(struct lp_setup_context *setup);
|
||||
|
||||
@@ -209,6 +223,15 @@ void lp_setup_destroy( struct lp_setup_context *setup );
|
||||
|
||||
boolean lp_setup_flush_and_restart(struct lp_setup_context *setup);
|
||||
|
||||
boolean
|
||||
lp_setup_whole_tile(struct lp_setup_context *setup,
|
||||
const struct lp_rast_shader_inputs *inputs,
|
||||
int tx, int ty);
|
||||
|
||||
boolean
|
||||
lp_setup_is_blit(const struct lp_setup_context *setup,
|
||||
const struct lp_rast_shader_inputs *inputs);
|
||||
|
||||
void
|
||||
lp_setup_print_triangle(struct lp_setup_context *setup,
|
||||
const float (*v0)[4],
|
||||
@@ -220,6 +243,19 @@ lp_setup_print_vertex(struct lp_setup_context *setup,
|
||||
const char *name,
|
||||
const float (*v)[4]);
|
||||
|
||||
void
|
||||
lp_rect_cw(struct lp_setup_context *setup,
|
||||
const float (*v0)[4],
|
||||
const float (*v1)[4],
|
||||
const float (*v2)[4],
|
||||
boolean frontfacing);
|
||||
|
||||
void
|
||||
lp_setup_triangle_ccw( struct lp_setup_context *setup,
|
||||
const float (*v0)[4],
|
||||
const float (*v1)[4],
|
||||
const float (*v2)[4],
|
||||
boolean front );
|
||||
|
||||
struct lp_rast_triangle *
|
||||
lp_setup_alloc_triangle(struct lp_scene *scene,
|
||||
@@ -227,6 +263,16 @@ lp_setup_alloc_triangle(struct lp_scene *scene,
|
||||
unsigned nr_planes,
|
||||
unsigned *tri_size);
|
||||
|
||||
struct lp_rast_rectangle *
|
||||
lp_setup_alloc_rectangle(struct lp_scene *scene,
|
||||
unsigned nr_inputs);
|
||||
|
||||
boolean
|
||||
lp_setup_analyse_triangles(struct lp_setup_context *setup,
|
||||
const void *vb,
|
||||
int stride,
|
||||
int nr);
|
||||
|
||||
boolean
|
||||
lp_setup_bin_triangle(struct lp_setup_context *setup,
|
||||
struct lp_rast_triangle *tri,
|
||||
@@ -235,4 +281,9 @@ lp_setup_bin_triangle(struct lp_setup_context *setup,
|
||||
int nr_planes,
|
||||
unsigned scissor_index);
|
||||
|
||||
boolean
|
||||
lp_setup_bin_rectangle(struct lp_setup_context *setup,
|
||||
struct lp_rast_rectangle *rect);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -586,15 +586,8 @@ try_setup_line( struct lp_setup_context *setup,
|
||||
bbox.y1--;
|
||||
}
|
||||
|
||||
if (bbox.x1 < bbox.x0 ||
|
||||
bbox.y1 < bbox.y0) {
|
||||
if (0) debug_printf("empty bounding box\n");
|
||||
LP_COUNT(nr_culled_tris);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (!u_rect_test_intersection(&setup->draw_regions[viewport_index], &bbox)) {
|
||||
if (0) debug_printf("offscreen\n");
|
||||
if (0) debug_printf("no intersection\n");
|
||||
LP_COUNT(nr_culled_tris);
|
||||
return TRUE;
|
||||
}
|
||||
@@ -611,9 +604,11 @@ try_setup_line( struct lp_setup_context *setup,
|
||||
* Determine how many scissor planes we need, that is drop scissor
|
||||
* edges if the bounding box of the tri is fully inside that edge.
|
||||
*/
|
||||
scissor = &setup->draw_regions[viewport_index];
|
||||
scissor_planes_needed(s_planes, &bboxpos, scissor);
|
||||
nr_planes += s_planes[0] + s_planes[1] + s_planes[2] + s_planes[3];
|
||||
if (setup->scissor_or_vp_clip) {
|
||||
scissor = &setup->draw_regions[viewport_index];
|
||||
scissor_planes_needed(s_planes, &bboxpos, scissor);
|
||||
nr_planes += s_planes[0] + s_planes[1] + s_planes[2] + s_planes[3];
|
||||
}
|
||||
|
||||
line = lp_setup_alloc_triangle(scene,
|
||||
key->num_inputs,
|
||||
|
||||
@@ -352,11 +352,8 @@ try_setup_point( struct lp_setup_context *setup,
|
||||
int adj = (setup->bottom_edge_rule != 0) ? 1 : 0;
|
||||
float pixel_offset = setup->multisample ? 0.0 : setup->pixel_offset;
|
||||
struct lp_scene *scene = setup->scene;
|
||||
struct lp_rast_triangle *point;
|
||||
unsigned bytes;
|
||||
struct u_rect bbox;
|
||||
int x[2], y[2];
|
||||
unsigned nr_planes = 4;
|
||||
struct point_info info;
|
||||
unsigned viewport_index = 0;
|
||||
unsigned layer = 0;
|
||||
@@ -461,56 +458,63 @@ try_setup_point( struct lp_setup_context *setup,
|
||||
}
|
||||
|
||||
if (!u_rect_test_intersection(&setup->draw_regions[viewport_index], &bbox)) {
|
||||
if (0) debug_printf("offscreen\n");
|
||||
if (0) debug_printf("no intersection\n");
|
||||
LP_COUNT(nr_culled_tris);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
u_rect_find_intersection(&setup->draw_regions[viewport_index], &bbox);
|
||||
|
||||
point = lp_setup_alloc_triangle(scene,
|
||||
key->num_inputs,
|
||||
nr_planes,
|
||||
&bytes);
|
||||
if (!point)
|
||||
return FALSE;
|
||||
|
||||
/* We can't use rectangle reasterizer for non-legacy points for now. */
|
||||
if (!setup->legacy_points || setup->multisample) {
|
||||
struct lp_rast_triangle *point;
|
||||
struct lp_rast_plane *plane;
|
||||
unsigned bytes;
|
||||
unsigned nr_planes = 4;
|
||||
|
||||
point = lp_setup_alloc_triangle(scene,
|
||||
key->num_inputs,
|
||||
nr_planes,
|
||||
&bytes);
|
||||
if (!point)
|
||||
return FALSE;
|
||||
|
||||
#ifdef DEBUG
|
||||
point->v[0][0] = v0[0][0];
|
||||
point->v[0][1] = v0[0][1];
|
||||
point->v[0][0] = v0[0][0];
|
||||
point->v[0][1] = v0[0][1];
|
||||
#endif
|
||||
|
||||
LP_COUNT(nr_tris);
|
||||
LP_COUNT(nr_tris);
|
||||
|
||||
if (draw_will_inject_frontface(lp_context->draw) &&
|
||||
setup->face_slot > 0) {
|
||||
point->inputs.frontfacing = v0[setup->face_slot][0];
|
||||
} else {
|
||||
point->inputs.frontfacing = TRUE;
|
||||
}
|
||||
if (draw_will_inject_frontface(lp_context->draw) &&
|
||||
setup->face_slot > 0) {
|
||||
point->inputs.frontfacing = v0[setup->face_slot][0];
|
||||
} else {
|
||||
point->inputs.frontfacing = TRUE;
|
||||
}
|
||||
|
||||
info.v0 = v0;
|
||||
info.dx01 = 0;
|
||||
info.dx12 = fixed_width;
|
||||
info.dy01 = fixed_width;
|
||||
info.dy12 = 0;
|
||||
info.a0 = GET_A0(&point->inputs);
|
||||
info.dadx = GET_DADX(&point->inputs);
|
||||
info.dady = GET_DADY(&point->inputs);
|
||||
info.frontfacing = point->inputs.frontfacing;
|
||||
info.v0 = v0;
|
||||
info.dx01 = 0;
|
||||
info.dx12 = fixed_width;
|
||||
info.dy01 = fixed_width;
|
||||
info.dy12 = 0;
|
||||
info.a0 = GET_A0(&point->inputs);
|
||||
info.dadx = GET_DADX(&point->inputs);
|
||||
info.dady = GET_DADY(&point->inputs);
|
||||
info.frontfacing = point->inputs.frontfacing;
|
||||
|
||||
/* Setup parameter interpolants:
|
||||
*/
|
||||
setup_point_coefficients(setup, &info);
|
||||
/* Setup parameter interpolants:
|
||||
*/
|
||||
setup_point_coefficients(setup, &info);
|
||||
|
||||
point->inputs.disable = FALSE;
|
||||
point->inputs.opaque = FALSE;
|
||||
point->inputs.layer = layer;
|
||||
point->inputs.viewport_index = viewport_index;
|
||||
point->inputs.view_index = setup->view_index;
|
||||
point->inputs.disable = FALSE;
|
||||
point->inputs.is_blit = FALSE;
|
||||
point->inputs.opaque = setup->fs.current.variant->opaque;
|
||||
point->inputs.layer = layer;
|
||||
point->inputs.viewport_index = viewport_index;
|
||||
point->inputs.view_index = setup->view_index;
|
||||
|
||||
{
|
||||
struct lp_rast_plane *plane = GET_PLANES(point);
|
||||
plane = GET_PLANES(point);
|
||||
|
||||
plane[0].dcdx = ~0U << 8;
|
||||
plane[0].dcdy = 0;
|
||||
@@ -540,9 +544,57 @@ try_setup_point( struct lp_setup_context *setup,
|
||||
else
|
||||
plane[3].c++; /* bottom-left */
|
||||
}
|
||||
}
|
||||
|
||||
return lp_setup_bin_triangle(setup, point, &bbox, &bbox, nr_planes, viewport_index);
|
||||
return lp_setup_bin_triangle(setup, point, &bbox, &bbox, nr_planes, viewport_index);
|
||||
|
||||
} else {
|
||||
struct lp_rast_rectangle *point;
|
||||
point = lp_setup_alloc_rectangle(scene,
|
||||
key->num_inputs);
|
||||
if (!point)
|
||||
return FALSE;
|
||||
#ifdef DEBUG
|
||||
point->v[0][0] = v0[0][0];
|
||||
point->v[0][1] = v0[0][1];
|
||||
#endif
|
||||
|
||||
point->box.x0 = bbox.x0;
|
||||
point->box.x1 = bbox.x1;
|
||||
point->box.y0 = bbox.y0;
|
||||
point->box.y1 = bbox.y1;
|
||||
|
||||
LP_COUNT(nr_tris);
|
||||
|
||||
if (draw_will_inject_frontface(lp_context->draw) &&
|
||||
setup->face_slot > 0) {
|
||||
point->inputs.frontfacing = v0[setup->face_slot][0];
|
||||
} else {
|
||||
point->inputs.frontfacing = TRUE;
|
||||
}
|
||||
|
||||
info.v0 = v0;
|
||||
info.dx01 = 0;
|
||||
info.dx12 = fixed_width;
|
||||
info.dy01 = fixed_width;
|
||||
info.dy12 = 0;
|
||||
info.a0 = GET_A0(&point->inputs);
|
||||
info.dadx = GET_DADX(&point->inputs);
|
||||
info.dady = GET_DADY(&point->inputs);
|
||||
info.frontfacing = point->inputs.frontfacing;
|
||||
|
||||
/* Setup parameter interpolants:
|
||||
*/
|
||||
setup_point_coefficients(setup, &info);
|
||||
|
||||
point->inputs.disable = FALSE;
|
||||
point->inputs.is_blit = FALSE;
|
||||
point->inputs.opaque = setup->fs.current.variant->opaque;
|
||||
point->inputs.layer = layer;
|
||||
point->inputs.viewport_index = viewport_index;
|
||||
point->inputs.view_index = setup->view_index;
|
||||
|
||||
return lp_setup_bin_rectangle(setup, point);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,900 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright 2010-2021 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 THE AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR
|
||||
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
**************************************************************************/
|
||||
|
||||
/**
|
||||
* Setup/binning code for screen-aligned quads.
|
||||
*/
|
||||
|
||||
#include "util/u_math.h"
|
||||
#include "util/u_memory.h"
|
||||
#include "lp_perf.h"
|
||||
#include "lp_setup_context.h"
|
||||
#include "lp_rast.h"
|
||||
#include "lp_state_fs.h"
|
||||
#include "lp_state_setup.h"
|
||||
|
||||
|
||||
#define NUM_CHANNELS 4
|
||||
|
||||
#define UNDETERMINED_BLIT -1
|
||||
|
||||
|
||||
static inline int
|
||||
subpixel_snap(float a)
|
||||
{
|
||||
return util_iround(FIXED_ONE * a);
|
||||
}
|
||||
|
||||
|
||||
static inline float
|
||||
fixed_to_float(int a)
|
||||
{
|
||||
return a * (1.0f / FIXED_ONE);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Alloc space for a new rectangle plus the input.a0/dadx/dady arrays
|
||||
* immediately after it.
|
||||
* The memory is allocated from the per-scene pool, not per-tile.
|
||||
* \param size returns number of bytes allocated
|
||||
* \param nr_inputs number of fragment shader inputs
|
||||
* \return pointer to rectangle space
|
||||
*/
|
||||
struct lp_rast_rectangle *
|
||||
lp_setup_alloc_rectangle(struct lp_scene *scene, unsigned nr_inputs)
|
||||
{
|
||||
unsigned input_array_sz = NUM_CHANNELS * (nr_inputs + 1) * sizeof(float);
|
||||
struct lp_rast_rectangle *rect;
|
||||
unsigned bytes;
|
||||
|
||||
bytes = sizeof(*rect) + (3 * input_array_sz);
|
||||
|
||||
rect = lp_scene_alloc_aligned( scene, bytes, 16 );
|
||||
if (rect == NULL)
|
||||
return NULL;
|
||||
|
||||
rect->inputs.stride = input_array_sz;
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The rectangle covers the whole tile- shade whole tile.
|
||||
* XXX no rectangle/triangle dependencies in this file - share it with
|
||||
* the same code in lp_setup_tri.c
|
||||
* \param tx, ty the tile position in tiles, not pixels
|
||||
*/
|
||||
boolean
|
||||
lp_setup_whole_tile(struct lp_setup_context *setup,
|
||||
const struct lp_rast_shader_inputs *inputs,
|
||||
int tx, int ty)
|
||||
{
|
||||
struct lp_scene *scene = setup->scene;
|
||||
|
||||
LP_COUNT(nr_fully_covered_64);
|
||||
|
||||
/* if variant is opaque and scissor doesn't effect the tile */
|
||||
if (inputs->opaque) {
|
||||
/* Several things prevent this optimization from working:
|
||||
* - For layered rendering we can't determine if this covers the same layer
|
||||
* as previous rendering (or in case of clears those actually always cover
|
||||
* all layers so optimization is impossible). Need to use fb_max_layer and
|
||||
* not setup->layer_slot to determine this since even if there's currently
|
||||
* no slot assigned previous rendering could have used one.
|
||||
* - If there were any Begin/End query commands in the scene then those
|
||||
* would get removed which would be very wrong. Furthermore, if queries
|
||||
* were just active we also can't do the optimization since to get
|
||||
* accurate query results we unfortunately need to execute the rendering
|
||||
* commands.
|
||||
*/
|
||||
if (!scene->fb.zsbuf && scene->fb_max_layer == 0 && !scene->had_queries) {
|
||||
/*
|
||||
* All previous rendering will be overwritten so reset the bin.
|
||||
*/
|
||||
lp_scene_bin_reset( scene, tx, ty );
|
||||
}
|
||||
|
||||
if (inputs->is_blit) {
|
||||
LP_COUNT(nr_blit_64);
|
||||
return lp_scene_bin_cmd_with_state( scene, tx, ty,
|
||||
setup->fs.stored,
|
||||
LP_RAST_OP_BLIT,
|
||||
lp_rast_arg_inputs(inputs) );
|
||||
}
|
||||
else {
|
||||
LP_COUNT(nr_shade_opaque_64);
|
||||
return lp_scene_bin_cmd_with_state( scene, tx, ty,
|
||||
setup->fs.stored,
|
||||
LP_RAST_OP_SHADE_TILE_OPAQUE,
|
||||
lp_rast_arg_inputs(inputs) );
|
||||
}
|
||||
}
|
||||
else {
|
||||
LP_COUNT(nr_shade_64);
|
||||
return lp_scene_bin_cmd_with_state( scene, tx, ty,
|
||||
setup->fs.stored,
|
||||
LP_RAST_OP_SHADE_TILE,
|
||||
lp_rast_arg_inputs(inputs) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
boolean
|
||||
lp_setup_is_blit(const struct lp_setup_context *setup,
|
||||
const struct lp_rast_shader_inputs *inputs)
|
||||
{
|
||||
const struct lp_fragment_shader_variant *variant =
|
||||
setup->fs.current.variant;
|
||||
|
||||
if (variant->blit) {
|
||||
/*
|
||||
* Detect blits.
|
||||
*/
|
||||
const struct lp_jit_texture *texture =
|
||||
&setup->fs.current.jit_context.textures[0];
|
||||
float dsdx, dsdy, dtdx, dtdy;
|
||||
|
||||
/* XXX: dadx vs dady confusion below?
|
||||
*/
|
||||
dsdx = GET_DADX(inputs)[1][0]*texture->width;
|
||||
dsdy = GET_DADX(inputs)[1][1]*texture->width;
|
||||
dtdx = GET_DADY(inputs)[1][0]*texture->height;
|
||||
dtdy = GET_DADY(inputs)[1][1]*texture->height;
|
||||
|
||||
/*
|
||||
* We don't need to check s0/t0 tolerances
|
||||
* as we establish as pre-condition that there is no
|
||||
* texture filtering.
|
||||
*/
|
||||
|
||||
assert(variant->key.samplers[0].sampler_state.min_img_filter == PIPE_TEX_FILTER_NEAREST);
|
||||
assert(variant->key.samplers[0].sampler_state.mag_img_filter == PIPE_TEX_FILTER_NEAREST);
|
||||
|
||||
/*
|
||||
* Check for 1:1 match of texels to dest pixels
|
||||
*/
|
||||
|
||||
if (util_is_approx(dsdx, 1.0f, 1.0f/LP_MAX_WIDTH) &&
|
||||
util_is_approx(dsdy, 0.0f, 1.0f/LP_MAX_HEIGHT) &&
|
||||
util_is_approx(dtdx, 0.0f, 1.0f/LP_MAX_WIDTH) &&
|
||||
util_is_approx(dtdy, 1.0f, 1.0f/LP_MAX_HEIGHT)) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
#if 0
|
||||
debug_printf("dsdx = %f\n", dsdx);
|
||||
debug_printf("dsdy = %f\n", dsdy);
|
||||
debug_printf("dtdx = %f\n", dtdx);
|
||||
debug_printf("dtdy = %f\n", dtdy);
|
||||
debug_printf("\n");
|
||||
#endif
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
static inline void
|
||||
partial(struct lp_setup_context *setup,
|
||||
const struct lp_rast_rectangle *rect,
|
||||
unsigned ix, unsigned iy,
|
||||
unsigned mask)
|
||||
{
|
||||
if (mask == 0) {
|
||||
assert(rect->box.x0 <= ix * TILE_SIZE);
|
||||
assert(rect->box.y0 <= iy * TILE_SIZE);
|
||||
assert(rect->box.x1 >= (ix+1) * TILE_SIZE - 1);
|
||||
assert(rect->box.y1 >= (iy+1) * TILE_SIZE - 1);
|
||||
|
||||
lp_setup_whole_tile(setup, &rect->inputs, ix, iy);
|
||||
}
|
||||
else {
|
||||
LP_COUNT(nr_partially_covered_64);
|
||||
lp_scene_bin_cmd_with_state( setup->scene,
|
||||
ix, iy,
|
||||
setup->fs.stored,
|
||||
LP_RAST_OP_RECTANGLE,
|
||||
lp_rast_arg_rectangle(rect) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Setup/bin a screen-aligned rect.
|
||||
* We need three corner vertices in order to correctly setup
|
||||
* interpolated parameters. We *could* get away with just the
|
||||
* diagonal vertices but it'd cause ugliness elsewhere.
|
||||
*
|
||||
* + -------v0
|
||||
* | |
|
||||
* v2 ------ v1
|
||||
*
|
||||
* By an unfortunate mixup between GL and D3D coordinate spaces, half
|
||||
* of this file talks about clockwise rectangles (which were CCW in GL
|
||||
* coordinate space), while the other half prefers to work with D3D
|
||||
* CCW rectangles.
|
||||
*/
|
||||
static boolean
|
||||
try_rect_cw(struct lp_setup_context *setup,
|
||||
const float (*v0)[4],
|
||||
const float (*v1)[4],
|
||||
const float (*v2)[4],
|
||||
boolean frontfacing)
|
||||
{
|
||||
const struct lp_fragment_shader_variant *variant =
|
||||
setup->fs.current.variant;
|
||||
const struct lp_setup_variant_key *key = &setup->setup.variant->key;
|
||||
struct lp_scene *scene = setup->scene;
|
||||
struct lp_rast_rectangle *rect;
|
||||
boolean cw;
|
||||
struct u_rect bbox;
|
||||
unsigned viewport_index = 0;
|
||||
unsigned layer = 0;
|
||||
const float (*pv)[4];
|
||||
|
||||
/* x/y positions in fixed point */
|
||||
int x0 = subpixel_snap(v0[0][0] - setup->pixel_offset);
|
||||
int x1 = subpixel_snap(v1[0][0] - setup->pixel_offset);
|
||||
int x2 = subpixel_snap(v2[0][0] - setup->pixel_offset);
|
||||
int y0 = subpixel_snap(v0[0][1] - setup->pixel_offset);
|
||||
int y1 = subpixel_snap(v1[0][1] - setup->pixel_offset);
|
||||
int y2 = subpixel_snap(v2[0][1] - setup->pixel_offset);
|
||||
|
||||
LP_COUNT(nr_rects);
|
||||
|
||||
/* Cull clockwise rects without overflowing.
|
||||
*/
|
||||
cw = (x2 < x1) ^ (y0 < y2);
|
||||
if (cw) {
|
||||
LP_COUNT(nr_culled_rects);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (setup->flatshade_first) {
|
||||
pv = v0;
|
||||
}
|
||||
else {
|
||||
pv = v2;
|
||||
}
|
||||
if (setup->viewport_index_slot > 0) {
|
||||
unsigned *udata = (unsigned*)pv[setup->viewport_index_slot];
|
||||
viewport_index = lp_clamp_viewport_idx(*udata);
|
||||
}
|
||||
if (setup->layer_slot > 0) {
|
||||
layer = *(unsigned*)pv[setup->layer_slot];
|
||||
layer = MIN2(layer, scene->fb_max_layer);
|
||||
}
|
||||
|
||||
/* Bounding rectangle (in pixels) */
|
||||
{
|
||||
/* Yes this is necessary to accurately calculate bounding boxes
|
||||
* with the two fill-conventions we support. GL (normally) ends
|
||||
* up needing a bottom-left fill convention, which requires
|
||||
* slightly different rounding.
|
||||
*/
|
||||
int adj = (setup->bottom_edge_rule != 0) ? 1 : 0;
|
||||
|
||||
bbox.x0 = (MIN3(x0, x1, x2) + (FIXED_ONE-1)) >> FIXED_ORDER;
|
||||
bbox.x1 = (MAX3(x0, x1, x2) + (FIXED_ONE-1)) >> FIXED_ORDER;
|
||||
bbox.y0 = (MIN3(y0, y1, y2) + (FIXED_ONE-1) + adj) >> FIXED_ORDER;
|
||||
bbox.y1 = (MAX3(y0, y1, y2) + (FIXED_ONE-1) + adj) >> FIXED_ORDER;
|
||||
|
||||
/* Inclusive coordinates:
|
||||
*/
|
||||
bbox.x1--;
|
||||
bbox.y1--;
|
||||
}
|
||||
|
||||
if (!u_rect_test_intersection(&setup->draw_regions[viewport_index], &bbox)) {
|
||||
if (0) debug_printf("no intersection\n");
|
||||
LP_COUNT(nr_culled_rects);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
u_rect_find_intersection(&setup->draw_regions[viewport_index], &bbox);
|
||||
|
||||
rect = lp_setup_alloc_rectangle(scene, key->num_inputs);
|
||||
if (!rect)
|
||||
return FALSE;
|
||||
|
||||
#ifdef DEBUG
|
||||
rect->v[0][0] = v0[0][0];
|
||||
rect->v[0][1] = v0[0][1];
|
||||
rect->v[1][0] = v1[0][0];
|
||||
rect->v[1][1] = v1[0][1];
|
||||
#endif
|
||||
|
||||
rect->box.x0 = bbox.x0;
|
||||
rect->box.x1 = bbox.x1;
|
||||
rect->box.y0 = bbox.y0;
|
||||
rect->box.y1 = bbox.y1;
|
||||
|
||||
/* Setup parameter interpolants:
|
||||
*/
|
||||
setup->setup.variant->jit_function( v0,
|
||||
v1,
|
||||
v2,
|
||||
frontfacing,
|
||||
GET_A0(&rect->inputs),
|
||||
GET_DADX(&rect->inputs),
|
||||
GET_DADY(&rect->inputs),
|
||||
&setup->setup.variant->key );
|
||||
|
||||
rect->inputs.frontfacing = frontfacing;
|
||||
rect->inputs.disable = FALSE;
|
||||
rect->inputs.is_blit = lp_setup_is_blit(setup, &rect->inputs);
|
||||
rect->inputs.opaque = variant->opaque;
|
||||
rect->inputs.layer = layer;
|
||||
rect->inputs.viewport_index = viewport_index;
|
||||
rect->inputs.view_index = setup->view_index;
|
||||
|
||||
return lp_setup_bin_rectangle(setup, rect);
|
||||
}
|
||||
|
||||
|
||||
boolean
|
||||
lp_setup_bin_rectangle(struct lp_setup_context *setup,
|
||||
struct lp_rast_rectangle *rect)
|
||||
{
|
||||
struct lp_scene *scene = setup->scene;
|
||||
unsigned ix0, iy0, ix1, iy1;
|
||||
unsigned i, j;
|
||||
unsigned left_mask = 0;
|
||||
unsigned right_mask = 0;
|
||||
unsigned top_mask = 0;
|
||||
unsigned bottom_mask = 0;
|
||||
|
||||
/*
|
||||
* All fields of 'rect' are now set. The remaining code here is
|
||||
* concerned with binning.
|
||||
*/
|
||||
|
||||
/* Convert to inclusive tile coordinates:
|
||||
*/
|
||||
ix0 = rect->box.x0 / TILE_SIZE;
|
||||
iy0 = rect->box.y0 / TILE_SIZE;
|
||||
ix1 = rect->box.x1 / TILE_SIZE;
|
||||
iy1 = rect->box.y1 / TILE_SIZE;
|
||||
|
||||
/*
|
||||
* Clamp to framebuffer size
|
||||
*/
|
||||
assert(ix0 == MAX2(ix0, 0));
|
||||
assert(iy0 == MAX2(iy0, 0));
|
||||
assert(ix1 == MIN2(ix1, scene->tiles_x - 1));
|
||||
assert(iy1 == MIN2(iy1, scene->tiles_y - 1));
|
||||
|
||||
if (ix0 * TILE_SIZE != rect->box.x0)
|
||||
left_mask = RECT_PLANE_LEFT;
|
||||
|
||||
if (ix1 * TILE_SIZE + TILE_SIZE - 1 != rect->box.x1)
|
||||
right_mask = RECT_PLANE_RIGHT;
|
||||
|
||||
if (iy0 * TILE_SIZE != rect->box.y0)
|
||||
top_mask = RECT_PLANE_TOP;
|
||||
|
||||
if (iy1 * TILE_SIZE + TILE_SIZE - 1 != rect->box.y1)
|
||||
bottom_mask = RECT_PLANE_BOTTOM;
|
||||
|
||||
/* Determine which tile(s) intersect the rectangle's bounding box
|
||||
*/
|
||||
if (iy0 == iy1 && ix0 == ix1) {
|
||||
partial(setup, rect, ix0, iy0,
|
||||
(left_mask | right_mask | top_mask | bottom_mask));
|
||||
}
|
||||
else if (ix0 == ix1) {
|
||||
unsigned mask = left_mask | right_mask;
|
||||
partial(setup, rect, ix0, iy0, mask | top_mask);
|
||||
for (i = iy0 + 1; i < iy1; i++)
|
||||
partial(setup, rect, ix0, i, mask);
|
||||
partial(setup, rect, ix0, iy1, mask | bottom_mask);
|
||||
}
|
||||
else if (iy0 == iy1) {
|
||||
unsigned mask = top_mask | bottom_mask;
|
||||
partial(setup, rect, ix0, iy0, mask | left_mask);
|
||||
for (i = ix0 + 1; i < ix1; i++)
|
||||
partial(setup, rect, i, iy0, mask);
|
||||
partial(setup, rect, ix1, iy0, mask | right_mask);
|
||||
}
|
||||
else {
|
||||
partial(setup, rect, ix0, iy0, left_mask | top_mask);
|
||||
partial(setup, rect, ix0, iy1, left_mask | bottom_mask);
|
||||
partial(setup, rect, ix1, iy0, right_mask | top_mask);
|
||||
partial(setup, rect, ix1, iy1, right_mask | bottom_mask);
|
||||
|
||||
/* Top/Bottom fringes
|
||||
*/
|
||||
for (i = ix0 + 1; i < ix1; i++) {
|
||||
partial(setup, rect, i, iy0, top_mask);
|
||||
partial(setup, rect, i, iy1, bottom_mask);
|
||||
}
|
||||
|
||||
/* Left/Right fringes
|
||||
*/
|
||||
for (i = iy0 + 1; i < iy1; i++) {
|
||||
partial(setup, rect, ix0, i, left_mask);
|
||||
partial(setup, rect, ix1, i, right_mask);
|
||||
}
|
||||
|
||||
/* Full interior tiles
|
||||
*/
|
||||
for (j = iy0 + 1; j < iy1; j++) {
|
||||
for (i = ix0 + 1; i < ix1; i++) {
|
||||
lp_setup_whole_tile(setup, &rect->inputs, i, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Catch any out-of-memory which occurred during binning. Do this
|
||||
* once here rather than checking all the return values throughout.
|
||||
*/
|
||||
if (lp_scene_is_oom(scene)) {
|
||||
/* Disable rasterization of this partially-binned rectangle.
|
||||
* We'll flush this scene and re-bin the entire rectangle:
|
||||
*/
|
||||
rect->inputs.disable = TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lp_rect_cw(struct lp_setup_context *setup,
|
||||
const float (*v0)[4],
|
||||
const float (*v1)[4],
|
||||
const float (*v2)[4],
|
||||
boolean frontfacing)
|
||||
{
|
||||
if (!try_rect_cw(setup, v0, v1, v2, frontfacing)) {
|
||||
if (!lp_setup_flush_and_restart(setup))
|
||||
return;
|
||||
|
||||
if (!try_rect_cw(setup, v0, v1, v2, frontfacing))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Take the six vertices for two triangles and try to determine if they
|
||||
* form a screen-aligned quad/rectangle. If so, draw the rect directly,
|
||||
* else, draw as two regular triangles.
|
||||
*/
|
||||
static boolean
|
||||
do_rect_ccw(struct lp_setup_context *setup,
|
||||
const float (*v0)[4],
|
||||
const float (*v1)[4],
|
||||
const float (*v2)[4],
|
||||
const float (*v3)[4],
|
||||
const float (*v4)[4],
|
||||
const float (*v5)[4],
|
||||
boolean front)
|
||||
{
|
||||
const float (*rv0)[4], (*rv1)[4], (*rv2)[4], (*rv3)[4]; /* rect verts */
|
||||
|
||||
#define SAME_POS(A, B) (A[0][0] == B[0][0] && \
|
||||
A[0][1] == B[0][1] && \
|
||||
A[0][2] == B[0][2] && \
|
||||
A[0][3] == B[0][3])
|
||||
|
||||
/* Only need to consider CCW orientations. There are nine ways
|
||||
* that two counter-clockwise triangles can join up:
|
||||
*/
|
||||
if (SAME_POS(v0, v3)) {
|
||||
if (SAME_POS(v2, v4)) {
|
||||
/*
|
||||
* v5 v4/v2
|
||||
* +-----+
|
||||
* | / |
|
||||
* | / |
|
||||
* | / |
|
||||
* +-----+
|
||||
* v3/v0 v1
|
||||
*/
|
||||
rv0 = v5;
|
||||
rv1 = v0;
|
||||
rv2 = v1;
|
||||
rv3 = v2;
|
||||
}
|
||||
else if (SAME_POS(v1, v5)) {
|
||||
/*
|
||||
* v4 v3/v0
|
||||
* +-----+
|
||||
* | / |
|
||||
* | / |
|
||||
* | / |
|
||||
* +-----+
|
||||
* v5/v1 v2
|
||||
*/
|
||||
rv0 = v4;
|
||||
rv1 = v1;
|
||||
rv2 = v2;
|
||||
rv3 = v0;
|
||||
}
|
||||
else {
|
||||
goto emit_triangles;
|
||||
}
|
||||
}
|
||||
else if (SAME_POS(v0, v5)) {
|
||||
if (SAME_POS(v2, v3)) {
|
||||
/*
|
||||
* v4 v3/v2
|
||||
* +-----+
|
||||
* | / |
|
||||
* | / |
|
||||
* | / |
|
||||
* +-----+
|
||||
* v5/v0 v1
|
||||
*/
|
||||
rv0 = v4;
|
||||
rv1 = v0;
|
||||
rv2 = v1;
|
||||
rv3 = v2;
|
||||
}
|
||||
else if (SAME_POS(v1, v4)) {
|
||||
/*
|
||||
* v3 v5/v0
|
||||
* +-----+
|
||||
* | / |
|
||||
* | / |
|
||||
* | / |
|
||||
* +-----+
|
||||
* v4/v1 v2
|
||||
*/
|
||||
rv0 = v3;
|
||||
rv1 = v1;
|
||||
rv2 = v2;
|
||||
rv3 = v0;
|
||||
}
|
||||
else {
|
||||
goto emit_triangles;
|
||||
}
|
||||
}
|
||||
else if (SAME_POS(v0, v4)) {
|
||||
if (SAME_POS(v2, v5)) {
|
||||
/*
|
||||
* v3 v5/v2
|
||||
* +-----+
|
||||
* | / |
|
||||
* | / |
|
||||
* | / |
|
||||
* +-----+
|
||||
* v4/v0 v1
|
||||
*/
|
||||
rv0 = v3;
|
||||
rv1 = v0;
|
||||
rv2 = v1;
|
||||
rv3 = v2;
|
||||
}
|
||||
else if (SAME_POS(v1, v3)) {
|
||||
/*
|
||||
* v5 v4/v0
|
||||
* +-----+
|
||||
* | / |
|
||||
* | / |
|
||||
* | / |
|
||||
* +-----+
|
||||
* v3/v1 v2
|
||||
*/
|
||||
rv0 = v5;
|
||||
rv1 = v1;
|
||||
rv2 = v2;
|
||||
rv3 = v0;
|
||||
}
|
||||
else {
|
||||
goto emit_triangles;
|
||||
}
|
||||
}
|
||||
else if (SAME_POS(v2, v3)) {
|
||||
if (SAME_POS(v1, v4)) {
|
||||
/*
|
||||
* v5 v4/v1
|
||||
* +-----+
|
||||
* | / |
|
||||
* | / |
|
||||
* | / |
|
||||
* +-----+
|
||||
* v3/v2 v0
|
||||
*/
|
||||
rv0 = v5;
|
||||
rv1 = v2;
|
||||
rv2 = v0;
|
||||
rv3 = v1;
|
||||
}
|
||||
else {
|
||||
goto emit_triangles;
|
||||
}
|
||||
}
|
||||
else if (SAME_POS(v2, v5)) {
|
||||
if (SAME_POS(v1, v3)) {
|
||||
/*
|
||||
* v4 v3/v1
|
||||
* +-----+
|
||||
* | / |
|
||||
* | / |
|
||||
* | / |
|
||||
* +-----+
|
||||
* v5/v2 v0
|
||||
*/
|
||||
rv0 = v4;
|
||||
rv1 = v2;
|
||||
rv2 = v0;
|
||||
rv3 = v1;
|
||||
}
|
||||
else {
|
||||
goto emit_triangles;
|
||||
}
|
||||
}
|
||||
else if (SAME_POS(v2, v4)) {
|
||||
if (SAME_POS(v1, v5)) {
|
||||
/*
|
||||
* v3 v5/v1
|
||||
* +-----+
|
||||
* | / |
|
||||
* | / |
|
||||
* | / |
|
||||
* +-----+
|
||||
* v4/v2 v0
|
||||
*/
|
||||
rv0 = v3;
|
||||
rv1 = v2;
|
||||
rv2 = v0;
|
||||
rv3 = v1;
|
||||
}
|
||||
else {
|
||||
goto emit_triangles;
|
||||
}
|
||||
}
|
||||
else {
|
||||
goto emit_triangles;
|
||||
}
|
||||
|
||||
|
||||
#define SAME_X(A, B) (A[0][0] == B[0][0])
|
||||
#define SAME_Y(A, B) (A[0][1] == B[0][1])
|
||||
|
||||
/* The vertices are now counter clockwise, as such:
|
||||
*
|
||||
* rv0 -------rv3
|
||||
* | |
|
||||
* rv1 ------ rv2
|
||||
*
|
||||
* To render as a rectangle,
|
||||
* * The X values should be the same at v0, v1 and v2, v3.
|
||||
* * The Y values should be the same at v0, v3 and v1, v2.
|
||||
*/
|
||||
if (SAME_Y(rv0, rv1)) {
|
||||
const float (*tmp)[4];
|
||||
tmp = rv0;
|
||||
rv0 = rv1;
|
||||
rv1 = rv2;
|
||||
rv2 = rv3;
|
||||
rv3 = tmp;
|
||||
}
|
||||
|
||||
if (SAME_X(rv0, rv1) && SAME_X(rv2, rv3) &&
|
||||
SAME_Y(rv0, rv3) && SAME_Y(rv1, rv2)) {
|
||||
|
||||
const struct lp_setup_variant_key *key = &setup->setup.variant->key;
|
||||
const unsigned n = key->num_inputs;
|
||||
unsigned i, j;
|
||||
|
||||
/* We have a rectangle. Check that the other attributes are
|
||||
* coplanar.
|
||||
*/
|
||||
for (i = 0; i < n; i++) {
|
||||
for (j = 0; j < 4; j++) {
|
||||
if (key->inputs[i].usage_mask & (1<<j)) {
|
||||
unsigned k = key->inputs[i].src_index;
|
||||
float dxdx1, dxdx2, dxdy1, dxdy2;
|
||||
dxdx1 = rv0[k][j] - rv3[k][j];
|
||||
dxdx2 = rv1[k][j] - rv2[k][j];
|
||||
dxdy1 = rv0[k][j] - rv1[k][j];
|
||||
dxdy2 = rv3[k][j] - rv2[k][j];
|
||||
if (dxdx1 != dxdx2 ||
|
||||
dxdy1 != dxdy2) {
|
||||
goto emit_triangles;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Note we're changing to clockwise here. Fix this by reworking
|
||||
* lp_rect_cw to expect/operate on ccw rects. Note that
|
||||
* function was previously misnamed.
|
||||
*/
|
||||
lp_rect_cw(setup, rv0, rv2, rv1, front);
|
||||
return TRUE;
|
||||
}
|
||||
else {
|
||||
/* setup->quad(setup, rv0, rv1, rv2, rv3); */
|
||||
}
|
||||
|
||||
emit_triangles:
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
enum winding {
|
||||
WINDING_NONE = 0,
|
||||
WINDING_CCW,
|
||||
WINDING_CW
|
||||
};
|
||||
|
||||
|
||||
static inline enum winding
|
||||
winding(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 */
|
||||
const float det = ex * fy - ey * fx;
|
||||
|
||||
if (det < 0.0f)
|
||||
return WINDING_CCW;
|
||||
else if (det > 0.0f)
|
||||
return WINDING_CW;
|
||||
else
|
||||
return WINDING_NONE;
|
||||
}
|
||||
|
||||
|
||||
static boolean
|
||||
setup_rect_cw(struct lp_setup_context *setup,
|
||||
const float (*v0)[4],
|
||||
const float (*v1)[4],
|
||||
const float (*v2)[4],
|
||||
const float (*v3)[4],
|
||||
const float (*v4)[4],
|
||||
const float (*v5)[4])
|
||||
{
|
||||
enum winding winding0 = winding(v0, v1, v2);
|
||||
enum winding winding1 = winding(v3, v4, v5);
|
||||
|
||||
if (winding0 == WINDING_CW &&
|
||||
winding1 == WINDING_CW) {
|
||||
return do_rect_ccw(setup, v0, v2, v1, v3, v5, v4, !setup->ccw_is_frontface);
|
||||
} else if (winding0 == WINDING_CW) {
|
||||
setup->triangle(setup, v0, v1, v2);
|
||||
return TRUE;
|
||||
} else if (winding1 == WINDING_CW) {
|
||||
setup->triangle(setup, v3, v4, v5);
|
||||
return TRUE;
|
||||
} else {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static boolean
|
||||
setup_rect_ccw(struct lp_setup_context *setup,
|
||||
const float (*v0)[4],
|
||||
const float (*v1)[4],
|
||||
const float (*v2)[4],
|
||||
const float (*v3)[4],
|
||||
const float (*v4)[4],
|
||||
const float (*v5)[4])
|
||||
{
|
||||
enum winding winding0 = winding(v0, v1, v2);
|
||||
enum winding winding1 = winding(v3, v4, v5);
|
||||
|
||||
if (winding0 == WINDING_CCW &&
|
||||
winding1 == WINDING_CCW) {
|
||||
return do_rect_ccw(setup, v0, v1, v2, v3, v4, v5, setup->ccw_is_frontface);
|
||||
} else if (winding0 == WINDING_CCW) {
|
||||
setup->triangle(setup, v0, v1, v2);
|
||||
return TRUE;
|
||||
} else if (winding1 == WINDING_CCW) {
|
||||
return FALSE;
|
||||
setup->triangle(setup, v3, v4, v5);
|
||||
return TRUE;
|
||||
} else {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static boolean
|
||||
setup_rect_noop(struct lp_setup_context *setup,
|
||||
const float (*v0)[4],
|
||||
const float (*v1)[4],
|
||||
const float (*v2)[4],
|
||||
const float (*v3)[4],
|
||||
const float (*v4)[4],
|
||||
const float (*v5)[4])
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static boolean
|
||||
setup_rect_both(struct lp_setup_context *setup,
|
||||
const float (*v0)[4],
|
||||
const float (*v1)[4],
|
||||
const float (*v2)[4],
|
||||
const float (*v3)[4],
|
||||
const float (*v4)[4],
|
||||
const float (*v5)[4])
|
||||
{
|
||||
enum winding winding0 = winding(v0, v1, v2);
|
||||
enum winding winding1 = winding(v3, v4, v5);
|
||||
|
||||
if (winding0 != winding1) {
|
||||
/* If we knew that the "front" parameter wasn't going to be
|
||||
* referenced, could rearrange one of the two triangles such
|
||||
* that they were both CCW. Aero actually does send mixed
|
||||
* CW/CCW rectangles under some circumstances, but we catch them
|
||||
* explicitly.
|
||||
*/
|
||||
return FALSE;
|
||||
}
|
||||
else if (winding0 == WINDING_CCW) {
|
||||
return do_rect_ccw(setup, v0, v1, v2, v3, v4, v5, setup->ccw_is_frontface);
|
||||
}
|
||||
else if (winding0 == WINDING_CW) {
|
||||
return do_rect_ccw(setup, v0, v2, v1, v3, v5, v4, !setup->ccw_is_frontface);
|
||||
} else {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lp_setup_choose_rect( struct lp_setup_context *setup )
|
||||
{
|
||||
if (setup->rasterizer_discard) {
|
||||
setup->rect = setup_rect_noop;
|
||||
return;
|
||||
}
|
||||
|
||||
switch (setup->cullmode) {
|
||||
case PIPE_FACE_NONE:
|
||||
setup->rect = setup_rect_both;
|
||||
break;
|
||||
case PIPE_FACE_BACK:
|
||||
setup->rect = setup->ccw_is_frontface ? setup_rect_ccw : setup_rect_cw;
|
||||
break;
|
||||
case PIPE_FACE_FRONT:
|
||||
setup->rect = setup->ccw_is_frontface ? setup_rect_cw : setup_rect_ccw;
|
||||
break;
|
||||
default:
|
||||
setup->rect = setup_rect_noop;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -205,6 +205,7 @@ lp_rast_32_tri_tab[MAX_PLANES+1] = {
|
||||
LP_RAST_OP_TRIANGLE_32_8
|
||||
};
|
||||
|
||||
|
||||
static unsigned
|
||||
lp_rast_ms_tri_tab[MAX_PLANES+1] = {
|
||||
0, /* should be impossible */
|
||||
@@ -218,56 +219,46 @@ lp_rast_ms_tri_tab[MAX_PLANES+1] = {
|
||||
LP_RAST_OP_MS_TRIANGLE_8
|
||||
};
|
||||
|
||||
/**
|
||||
* The primitive covers the whole tile- shade whole tile.
|
||||
/*
|
||||
* Detect big primitives drawn with an alpha == 1.0.
|
||||
*
|
||||
* \param tx, ty the tile position in tiles, not pixels
|
||||
* This is used when simulating anti-aliasing primitives in shaders, e.g.,
|
||||
* when drawing the windows client area in Aero's flip-3d effect.
|
||||
*/
|
||||
static boolean
|
||||
lp_setup_whole_tile(struct lp_setup_context *setup,
|
||||
const struct lp_rast_shader_inputs *inputs,
|
||||
int tx, int ty)
|
||||
check_opaque(struct lp_setup_context *setup,
|
||||
const float (*v1)[4],
|
||||
const float (*v2)[4],
|
||||
const float (*v3)[4])
|
||||
{
|
||||
struct lp_scene *scene = setup->scene;
|
||||
const struct lp_fragment_shader_variant *variant =
|
||||
setup->fs.current.variant;
|
||||
const struct lp_tgsi_channel_info *alpha_info = &variant->shader->info.cbuf[0][3];
|
||||
|
||||
LP_COUNT(nr_fully_covered_64);
|
||||
if (variant->opaque)
|
||||
return TRUE;
|
||||
|
||||
if (!variant->potentially_opaque)
|
||||
return FALSE;
|
||||
|
||||
/* if variant is opaque and scissor doesn't effect the tile */
|
||||
if (inputs->opaque) {
|
||||
/* Several things prevent this optimization from working:
|
||||
* - For layered rendering we can't determine if this covers the same layer
|
||||
* as previous rendering (or in case of clears those actually always cover
|
||||
* all layers so optimization is impossible). Need to use fb_max_layer and
|
||||
* not setup->layer_slot to determine this since even if there's currently
|
||||
* no slot assigned previous rendering could have used one.
|
||||
* - If there were any Begin/End query commands in the scene then those
|
||||
* would get removed which would be very wrong. Furthermore, if queries
|
||||
* were just active we also can't do the optimization since to get
|
||||
* accurate query results we unfortunately need to execute the rendering
|
||||
* commands.
|
||||
*/
|
||||
if (!scene->fb.zsbuf && scene->fb_max_layer == 0 && !scene->had_queries) {
|
||||
/*
|
||||
* All previous rendering will be overwritten so reset the bin.
|
||||
*/
|
||||
lp_scene_bin_reset( scene, tx, ty );
|
||||
}
|
||||
|
||||
LP_COUNT(nr_shade_opaque_64);
|
||||
return lp_scene_bin_cmd_with_state( scene, tx, ty,
|
||||
setup->fs.stored,
|
||||
LP_RAST_OP_SHADE_TILE_OPAQUE,
|
||||
lp_rast_arg_inputs(inputs) );
|
||||
} else {
|
||||
LP_COUNT(nr_shade_64);
|
||||
return lp_scene_bin_cmd_with_state( scene, tx, ty,
|
||||
setup->fs.stored,
|
||||
LP_RAST_OP_SHADE_TILE,
|
||||
lp_rast_arg_inputs(inputs) );
|
||||
if (alpha_info->file == TGSI_FILE_CONSTANT) {
|
||||
const float *constants = setup->fs.current.jit_context.constants[0];
|
||||
float alpha = constants[alpha_info->u.index*4 +
|
||||
alpha_info->swizzle];
|
||||
return alpha == 1.0f;
|
||||
}
|
||||
|
||||
if (alpha_info->file == TGSI_FILE_INPUT) {
|
||||
return (v1[1 + alpha_info->u.index][alpha_info->swizzle] == 1.0f &&
|
||||
v2[1 + alpha_info->u.index][alpha_info->swizzle] == 1.0f &&
|
||||
v3[1 + alpha_info->u.index][alpha_info->swizzle] == 1.0f);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Do basic setup for triangle rasterization and determine which
|
||||
* framebuffer tiles are touched. Put the triangle in the scene's
|
||||
@@ -333,15 +324,8 @@ do_triangle_ccw(struct lp_setup_context *setup,
|
||||
bbox.y1 = (MAX3(position->y[0], position->y[1], position->y[2]) - 1 + adj) >> FIXED_ORDER;
|
||||
}
|
||||
|
||||
if (bbox.x1 < bbox.x0 ||
|
||||
bbox.y1 < bbox.y0) {
|
||||
if (0) debug_printf("empty bounding box\n");
|
||||
LP_COUNT(nr_culled_tris);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (!u_rect_test_intersection(&setup->draw_regions[viewport_index], &bbox)) {
|
||||
if (0) debug_printf("offscreen\n");
|
||||
if (0) debug_printf("no intersection\n");
|
||||
LP_COUNT(nr_culled_tris);
|
||||
return TRUE;
|
||||
}
|
||||
@@ -360,9 +344,11 @@ do_triangle_ccw(struct lp_setup_context *setup,
|
||||
* Determine how many scissor planes we need, that is drop scissor
|
||||
* edges if the bounding box of the tri is fully inside that edge.
|
||||
*/
|
||||
scissor = &setup->draw_regions[viewport_index];
|
||||
scissor_planes_needed(s_planes, &bboxpos, scissor);
|
||||
nr_planes += s_planes[0] + s_planes[1] + s_planes[2] + s_planes[3];
|
||||
if (setup->scissor_or_vp_clip) {
|
||||
scissor = &setup->draw_regions[viewport_index];
|
||||
scissor_planes_needed(s_planes, &bboxpos, scissor);
|
||||
nr_planes += s_planes[0] + s_planes[1] + s_planes[2] + s_planes[3];
|
||||
}
|
||||
|
||||
tri = lp_setup_alloc_triangle(scene,
|
||||
key->num_inputs,
|
||||
@@ -382,17 +368,97 @@ do_triangle_ccw(struct lp_setup_context *setup,
|
||||
|
||||
LP_COUNT(nr_tris);
|
||||
|
||||
/*
|
||||
* Rotate the tri such that v0 is closest to the fb origin.
|
||||
* This can give more accurate a0 value (which is at fb origin)
|
||||
* when calculating the interpolants.
|
||||
* It can't work when there's flat shading for instance in one
|
||||
* of the attributes, hence restrict this to just a single attribute
|
||||
* which is what causes some test failures.
|
||||
* (This does not address the problem that interpolation may be
|
||||
* inaccurate if gradients are relatively steep in small tris far
|
||||
* away from the origin. It does however fix the (silly) wgf11rasterizer
|
||||
* Interpolator test.)
|
||||
* XXX This causes problems with mipgen -EmuTexture for not yet really
|
||||
* understood reasons (if the vertices would be submitted in a different
|
||||
* order, we'd also generate the same "wrong" results here without
|
||||
* rotation). In any case, that we generate different values if a prim
|
||||
* has the vertices rotated but is otherwise the same (which is due to
|
||||
* numerical issues) is not a nice property. An additional problem by
|
||||
* swapping the vertices here (which is possibly worse) is that
|
||||
* the same primitive coming in twice might generate different values
|
||||
* (in particular for z) due to the swapping potentially not happening
|
||||
* both times, if the attributes to be interpolated are different. For now,
|
||||
* just restrict this to not get used with dx9 (by checking pixel offset),
|
||||
* could also restrict it further to only trigger with wgf11Interpolator
|
||||
* Rasterizer test (the only place which needs it, with always the same
|
||||
* vertices even).
|
||||
*/
|
||||
if ((LP_DEBUG & DEBUG_ACCURATE_A0) &&
|
||||
setup->pixel_offset == 0.5f &&
|
||||
key->num_inputs == 1 &&
|
||||
(key->inputs[0].interp == LP_INTERP_LINEAR ||
|
||||
key->inputs[0].interp == LP_INTERP_PERSPECTIVE)) {
|
||||
float dist0 = v0[0][0] * v0[0][0] + v0[0][1] * v0[0][1];
|
||||
float dist1 = v1[0][0] * v1[0][0] + v1[0][1] * v1[0][1];
|
||||
float dist2 = v2[0][0] * v2[0][0] + v2[0][1] * v2[0][1];
|
||||
if (dist0 > dist1 && dist1 < dist2) {
|
||||
const float (*vt)[4];
|
||||
int x, y;
|
||||
vt = v0;
|
||||
v0 = v1;
|
||||
v1 = v2;
|
||||
v2 = vt;
|
||||
x = position->x[0];
|
||||
y = position->y[0];
|
||||
position->x[0] = position->x[1];
|
||||
position->y[0] = position->y[1];
|
||||
position->x[1] = position->x[2];
|
||||
position->y[1] = position->y[2];
|
||||
position->x[2] = x;
|
||||
position->y[2] = y;
|
||||
|
||||
position->dx20 = position->dx01;
|
||||
position->dy20 = position->dy01;
|
||||
position->dx01 = position->x[0] - position->x[1];
|
||||
position->dy01 = position->y[0] - position->y[1];
|
||||
}
|
||||
else if (dist0 > dist2) {
|
||||
const float (*vt)[4];
|
||||
int x, y;
|
||||
vt = v0;
|
||||
v0 = v2;
|
||||
v2 = v1;
|
||||
v1 = vt;
|
||||
x = position->x[0];
|
||||
y = position->y[0];
|
||||
position->x[0] = position->x[2];
|
||||
position->y[0] = position->y[2];
|
||||
position->x[2] = position->x[1];
|
||||
position->y[2] = position->y[1];
|
||||
position->x[1] = x;
|
||||
position->y[1] = y;
|
||||
|
||||
position->dx01 = position->dx20;
|
||||
position->dy01 = position->dy20;
|
||||
position->dx20 = position->x[2] - position->x[0];
|
||||
position->dy20 = position->y[2] - position->y[0];
|
||||
}
|
||||
}
|
||||
|
||||
/* Setup parameter interpolants:
|
||||
*/
|
||||
setup->setup.variant->jit_function(v0, v1, v2,
|
||||
frontfacing,
|
||||
GET_A0(&tri->inputs),
|
||||
GET_DADX(&tri->inputs),
|
||||
GET_DADY(&tri->inputs));
|
||||
GET_DADY(&tri->inputs),
|
||||
&setup->setup.variant->key);
|
||||
|
||||
tri->inputs.frontfacing = frontfacing;
|
||||
tri->inputs.disable = FALSE;
|
||||
tri->inputs.opaque = setup->fs.current.variant->opaque;
|
||||
tri->inputs.is_blit = FALSE;
|
||||
tri->inputs.opaque = check_opaque(setup, v0, v1, v2);
|
||||
tri->inputs.layer = layer;
|
||||
tri->inputs.viewport_index = viewport_index;
|
||||
tri->inputs.view_index = setup->view_index;
|
||||
@@ -693,7 +759,6 @@ do_triangle_ccw(struct lp_setup_context *setup,
|
||||
* (easier to evaluate) to ordinary planes.)
|
||||
*/
|
||||
if (nr_planes > 3) {
|
||||
/* why not just use draw_regions */
|
||||
struct lp_rast_plane *plane_s = &plane[3];
|
||||
|
||||
if (s_planes[0]) {
|
||||
@@ -912,8 +977,8 @@ lp_setup_bin_triangle(struct lp_setup_context *setup,
|
||||
ystep[i] = ((int64_t)plane[i].dcdy) << TILE_ORDER;
|
||||
}
|
||||
|
||||
|
||||
|
||||
tri->inputs.is_blit = lp_setup_is_blit(setup, &tri->inputs);
|
||||
|
||||
/* Test tile-sized blocks against the triangle.
|
||||
* Discard blocks fully outside the tri. If the block is fully
|
||||
* contained inside the tri, bin an lp_rast_shade_tile command.
|
||||
|
||||
@@ -41,9 +41,16 @@
|
||||
#include "draw/draw_vbuf.h"
|
||||
#include "draw/draw_vertex.h"
|
||||
#include "util/u_memory.h"
|
||||
#include "util/u_math.h"
|
||||
#include "lp_state_fs.h"
|
||||
#include "lp_perf.h"
|
||||
|
||||
|
||||
#define LP_MAX_VBUF_INDEXES 1024
|
||||
/* It should be a multiple of both 6 and 4 (in other words, a multiple of 12)
|
||||
* to ensure draw splits between a whole number of rectangles.
|
||||
*/
|
||||
#define LP_MAX_VBUF_INDEXES 1020
|
||||
|
||||
#define LP_MAX_VBUF_SIZE 4096
|
||||
|
||||
|
||||
@@ -135,6 +142,22 @@ static inline const_float4_ptr get_vert( const void *vertex_buffer,
|
||||
return (const_float4_ptr)((char *)vertex_buffer + index * stride);
|
||||
}
|
||||
|
||||
static inline void
|
||||
rect(struct lp_setup_context *setup,
|
||||
const float (*v0)[4],
|
||||
const float (*v1)[4],
|
||||
const float (*v2)[4],
|
||||
const float (*v3)[4],
|
||||
const float (*v4)[4],
|
||||
const float (*v5)[4])
|
||||
{
|
||||
if (!setup->permit_linear_rasterizer ||
|
||||
!setup->rect( setup, v0, v1, v2, v3, v4, v5)) {
|
||||
setup->triangle(setup, v0, v1, v2);
|
||||
setup->triangle(setup, v3, v4, v5);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* draw elements / indexed primitives
|
||||
*/
|
||||
@@ -145,6 +168,7 @@ lp_setup_draw_elements(struct vbuf_render *vbr, const ushort *indices, uint nr)
|
||||
const unsigned stride = setup->vertex_info->size * sizeof(float);
|
||||
const void *vertex_buffer = setup->vertex_buffer;
|
||||
const boolean flatshade_first = setup->flatshade_first;
|
||||
boolean uses_constant_interp;
|
||||
unsigned i;
|
||||
|
||||
assert(setup->setup.variant);
|
||||
@@ -152,6 +176,8 @@ lp_setup_draw_elements(struct vbuf_render *vbr, const ushort *indices, uint nr)
|
||||
if (!lp_setup_update_state(setup, TRUE))
|
||||
return;
|
||||
|
||||
uses_constant_interp = setup->setup.variant->key.uses_constant_interp;
|
||||
|
||||
switch (setup->prim) {
|
||||
case PIPE_PRIM_POINTS:
|
||||
for (i = 0; i < nr; i++) {
|
||||
@@ -190,11 +216,24 @@ lp_setup_draw_elements(struct vbuf_render *vbr, const ushort *indices, uint nr)
|
||||
break;
|
||||
|
||||
case PIPE_PRIM_TRIANGLES:
|
||||
for (i = 2; i < nr; i += 3) {
|
||||
setup->triangle( setup,
|
||||
if (nr % 6 == 0 && !uses_constant_interp) {
|
||||
for (i = 5; i < nr; i += 6) {
|
||||
rect( setup,
|
||||
get_vert(vertex_buffer, indices[i-5], stride),
|
||||
get_vert(vertex_buffer, indices[i-4], stride),
|
||||
get_vert(vertex_buffer, indices[i-3], stride),
|
||||
get_vert(vertex_buffer, indices[i-2], stride),
|
||||
get_vert(vertex_buffer, indices[i-1], stride),
|
||||
get_vert(vertex_buffer, indices[i-0], 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;
|
||||
|
||||
@@ -345,11 +384,14 @@ lp_setup_draw_arrays(struct vbuf_render *vbr, uint start, uint nr)
|
||||
const void *vertex_buffer =
|
||||
(void *) get_vert(setup->vertex_buffer, start, stride);
|
||||
const boolean flatshade_first = setup->flatshade_first;
|
||||
boolean uses_constant_interp;
|
||||
unsigned i;
|
||||
|
||||
if (!lp_setup_update_state(setup, TRUE))
|
||||
return;
|
||||
|
||||
uses_constant_interp = setup->setup.variant->key.uses_constant_interp;
|
||||
|
||||
switch (setup->prim) {
|
||||
case PIPE_PRIM_POINTS:
|
||||
for (i = 0; i < nr; i++) {
|
||||
@@ -388,22 +430,74 @@ lp_setup_draw_arrays(struct vbuf_render *vbr, uint start, uint nr)
|
||||
break;
|
||||
|
||||
case PIPE_PRIM_TRIANGLES:
|
||||
for (i = 2; i < nr; i += 3) {
|
||||
setup->triangle( setup,
|
||||
if (nr % 6 == 0 && !uses_constant_interp) {
|
||||
for (i = 5; i < nr; i += 6) {
|
||||
rect( setup,
|
||||
get_vert(vertex_buffer, i-5, stride),
|
||||
get_vert(vertex_buffer, i-4, stride),
|
||||
get_vert(vertex_buffer, i-3, stride),
|
||||
get_vert(vertex_buffer, i-2, stride),
|
||||
get_vert(vertex_buffer, i-1, stride),
|
||||
get_vert(vertex_buffer, i-0, stride) );
|
||||
}
|
||||
}
|
||||
else if (!uses_constant_interp &&
|
||||
lp_setup_analyse_triangles(setup, vertex_buffer, stride, nr)) {
|
||||
/* If lp_setup_analyse_triangles() returned true, it also
|
||||
* emitted (setup) the rect or triangles.
|
||||
*/
|
||||
}
|
||||
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 (flatshade_first) {
|
||||
for (i = 2; i < nr; i++) {
|
||||
/* emit first triangle vertex as first triangle vertex */
|
||||
setup->triangle( setup,
|
||||
get_vert(vertex_buffer, i-2, stride),
|
||||
get_vert(vertex_buffer, i+(i&1)-1, stride),
|
||||
get_vert(vertex_buffer, i-(i&1), stride) );
|
||||
if (!uses_constant_interp) {
|
||||
int j;
|
||||
i = 2;
|
||||
j = 3;
|
||||
while (j < nr) {
|
||||
/* emit first triangle vertex as first triangle vertex */
|
||||
const float (*v0)[4] = get_vert(vertex_buffer, i-2, stride);
|
||||
const float (*v1)[4] = get_vert(vertex_buffer, i+(i&1)-1, stride);
|
||||
const float (*v2)[4] = get_vert(vertex_buffer, i-(i&1), stride);
|
||||
const float (*v3)[4] = get_vert(vertex_buffer, j-2, stride);
|
||||
const float (*v4)[4] = get_vert(vertex_buffer, j+(j&1)-1, stride);
|
||||
const float (*v5)[4] = get_vert(vertex_buffer, j-(j&1), stride);
|
||||
if (setup->permit_linear_rasterizer &&
|
||||
setup->rect(setup, v0, v1, v2, v3, v4, v5)) {
|
||||
i += 2;
|
||||
j += 2;
|
||||
} else {
|
||||
/* emit one triangle, and retry rectangle in the next one */
|
||||
setup->triangle(setup, v0, v1, v2);
|
||||
i += 1;
|
||||
j += 1;
|
||||
}
|
||||
}
|
||||
if (i < nr) {
|
||||
/* emit last triangle */
|
||||
setup->triangle( setup,
|
||||
get_vert(vertex_buffer, i-2, stride),
|
||||
get_vert(vertex_buffer, i+(i&1)-1, stride),
|
||||
get_vert(vertex_buffer, i-(i&1), stride) );
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (i = 2; i < nr; i++) {
|
||||
/* emit first triangle vertex as first triangle vertex */
|
||||
setup->triangle( setup,
|
||||
get_vert(vertex_buffer, i-2, stride),
|
||||
get_vert(vertex_buffer, i+(i&1)-1, stride),
|
||||
get_vert(vertex_buffer, i-(i&1), stride) );
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -418,7 +512,16 @@ lp_setup_draw_arrays(struct vbuf_render *vbr, uint start, uint nr)
|
||||
break;
|
||||
|
||||
case PIPE_PRIM_TRIANGLE_FAN:
|
||||
if (flatshade_first) {
|
||||
if (nr == 4 && !uses_constant_interp) {
|
||||
rect( setup,
|
||||
get_vert(vertex_buffer, 0, stride),
|
||||
get_vert(vertex_buffer, 1, stride),
|
||||
get_vert(vertex_buffer, 2, stride),
|
||||
get_vert(vertex_buffer, 0, stride),
|
||||
get_vert(vertex_buffer, 2, stride),
|
||||
get_vert(vertex_buffer, 3, stride) );
|
||||
}
|
||||
else if (flatshade_first) {
|
||||
for (i = 2; i < nr; i += 1) {
|
||||
/* emit first non-spoke vertex as first vertex */
|
||||
setup->triangle( setup,
|
||||
@@ -455,15 +558,28 @@ lp_setup_draw_arrays(struct vbuf_render *vbr, uint start, uint nr)
|
||||
}
|
||||
else {
|
||||
/* emit last quad vertex as last triangle vertex */
|
||||
for (i = 3; i < nr; i += 4) {
|
||||
setup->triangle( setup,
|
||||
if (!uses_constant_interp) {
|
||||
for (i = 3; i < nr; i += 4) {
|
||||
rect( 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-3, stride),
|
||||
get_vert(vertex_buffer, i-1, stride),
|
||||
get_vert(vertex_buffer, i-0, 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;
|
||||
|
||||
@@ -116,6 +116,9 @@ llvmpipe_update_fs(struct llvmpipe_context *lp);
|
||||
void
|
||||
llvmpipe_update_setup(struct llvmpipe_context *lp);
|
||||
|
||||
void
|
||||
llvmpipe_update_derived_clear(struct llvmpipe_context *llvmpipe);
|
||||
|
||||
void
|
||||
llvmpipe_update_derived(struct llvmpipe_context *llvmpipe);
|
||||
|
||||
|
||||
@@ -177,6 +177,8 @@ llvmpipe_set_sample_mask(struct pipe_context *pipe,
|
||||
struct llvmpipe_context *llvmpipe = llvmpipe_context(pipe);
|
||||
|
||||
if (sample_mask != llvmpipe->sample_mask) {
|
||||
draw_flush(llvmpipe->draw);
|
||||
|
||||
llvmpipe->sample_mask = sample_mask;
|
||||
|
||||
llvmpipe->dirty |= LP_NEW_SAMPLE_MASK;
|
||||
|
||||
@@ -173,6 +173,73 @@ compute_vertex_info(struct llvmpipe_context *llvmpipe)
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
check_linear_rasterizer( struct llvmpipe_context *lp )
|
||||
{
|
||||
boolean bgr8;
|
||||
boolean permit_linear;
|
||||
boolean single_vp;
|
||||
boolean clipping_changed = FALSE;
|
||||
|
||||
bgr8 = (lp->framebuffer.nr_cbufs == 1 &&
|
||||
lp->framebuffer.cbufs[0]->texture->target == PIPE_TEXTURE_2D &&
|
||||
(lp->framebuffer.cbufs[0]->format == PIPE_FORMAT_B8G8R8A8_UNORM ||
|
||||
lp->framebuffer.cbufs[0]->format == PIPE_FORMAT_B8G8R8X8_UNORM));
|
||||
|
||||
/* permit_linear means guardband, hence fake scissor, which we can only
|
||||
* handle if there's just one vp. */
|
||||
single_vp = lp->viewport_index_slot < 0;
|
||||
permit_linear = (!lp->framebuffer.zsbuf &&
|
||||
bgr8 &&
|
||||
single_vp);
|
||||
|
||||
/* Tell draw that we're happy doing our own x/y clipping.
|
||||
*/
|
||||
if (lp->permit_linear_rasterizer != permit_linear) {
|
||||
lp->permit_linear_rasterizer = permit_linear;
|
||||
lp_setup_set_linear_mode(lp->setup, permit_linear);
|
||||
clipping_changed = TRUE;
|
||||
}
|
||||
|
||||
if (lp->single_vp != single_vp) {
|
||||
lp->single_vp = single_vp;
|
||||
clipping_changed = TRUE;
|
||||
}
|
||||
|
||||
/* Disable xy clipping in linear mode.
|
||||
*
|
||||
* Use a guard band if we don't have zsbuf. Could enable
|
||||
* guardband always - this just to be conservative.
|
||||
*
|
||||
* Because we have a layering violation where the draw module emits
|
||||
* state changes to the driver while we're already inside a draw
|
||||
* call, need to be careful about when we make calls back to the
|
||||
* draw module. Hence the clipping_changed flag which is as much
|
||||
* to prevent flush recursion as it is to short-circuit noop state
|
||||
* changes.
|
||||
*/
|
||||
if (clipping_changed) {
|
||||
draw_set_driver_clipping(lp->draw,
|
||||
FALSE,
|
||||
FALSE,
|
||||
permit_linear,
|
||||
single_vp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handle state changes before clears.
|
||||
* Called just prior to clearing (pipe::clear()).
|
||||
*/
|
||||
void llvmpipe_update_derived_clear( struct llvmpipe_context *llvmpipe )
|
||||
{
|
||||
if (llvmpipe->dirty & (LP_NEW_FS |
|
||||
LP_NEW_FRAMEBUFFER))
|
||||
check_linear_rasterizer(llvmpipe);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handle state changes.
|
||||
* Called just prior to drawing anything (pipe::draw_arrays(), etc).
|
||||
@@ -293,6 +360,8 @@ void llvmpipe_update_derived( struct llvmpipe_context *llvmpipe )
|
||||
llvmpipe->viewports);
|
||||
}
|
||||
|
||||
llvmpipe_update_derived_clear(llvmpipe);
|
||||
|
||||
llvmpipe->dirty = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -589,7 +589,7 @@ generate_fs_loop(struct gallivm_state *gallivm,
|
||||
LLVMValueRef stencil_refs[2];
|
||||
LLVMValueRef outputs[PIPE_MAX_SHADER_OUTPUTS][TGSI_NUM_CHANNELS];
|
||||
LLVMValueRef zs_samples = lp_build_const_int32(gallivm, key->zsbuf_nr_samples);
|
||||
struct lp_build_for_loop_state loop_state, sample_loop_state;
|
||||
struct lp_build_for_loop_state loop_state, sample_loop_state = {0};
|
||||
struct lp_build_mask_context mask;
|
||||
/*
|
||||
* TODO: figure out if simple_shader optimization is really worthwile to
|
||||
@@ -3441,6 +3441,24 @@ dump_fs_variant_key(struct lp_fragment_shader_variant_key *key)
|
||||
}
|
||||
}
|
||||
|
||||
const char *
|
||||
lp_debug_fs_kind(enum lp_fs_kind kind)
|
||||
{
|
||||
switch(kind) {
|
||||
case LP_FS_KIND_GENERAL:
|
||||
return "GENERAL";
|
||||
case LP_FS_KIND_BLIT_RGBA:
|
||||
return "BLIT_RGBA";
|
||||
case LP_FS_KIND_BLIT_RGB1:
|
||||
return "BLIT_RGB1";
|
||||
case LP_FS_KIND_AERO_MINIFICATION:
|
||||
return "AERO_MINIFICATION";
|
||||
case LP_FS_KIND_LLVM_LINEAR:
|
||||
return "LLVM_LINEAR";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
lp_debug_fs_variant(struct lp_fragment_shader_variant *variant)
|
||||
@@ -3453,6 +3471,9 @@ lp_debug_fs_variant(struct lp_fragment_shader_variant *variant)
|
||||
nir_print_shader(variant->shader->base.ir.nir, stderr);
|
||||
dump_fs_variant_key(&variant->key);
|
||||
debug_printf("variant->opaque = %u\n", variant->opaque);
|
||||
debug_printf("variant->potentially_opaque = %u\n", variant->potentially_opaque);
|
||||
debug_printf("variant->blit = %u\n", variant->blit);
|
||||
debug_printf("shader->kind = %s\n", lp_debug_fs_kind(variant->shader->kind));
|
||||
debug_printf("\n");
|
||||
}
|
||||
|
||||
@@ -3491,6 +3512,8 @@ generate_variant(struct llvmpipe_context *lp,
|
||||
struct lp_fragment_shader_variant *variant;
|
||||
const struct util_format_description *cbuf0_format_desc = NULL;
|
||||
boolean fullcolormask;
|
||||
boolean no_kill;
|
||||
boolean linear;
|
||||
char module_name[64];
|
||||
unsigned char ir_sha1_cache_key[20];
|
||||
struct lp_cached_code cached = { 0 };
|
||||
@@ -3536,9 +3559,9 @@ generate_variant(struct llvmpipe_context *lp,
|
||||
fullcolormask = util_format_colormask_full(cbuf0_format_desc, key->blend.rt[0].colormask);
|
||||
}
|
||||
|
||||
variant->opaque =
|
||||
!key->blend.logicop_enable &&
|
||||
!key->blend.rt[0].blend_enable &&
|
||||
/* The scissor is ignored here as only tiles inside the scissoring
|
||||
* rectangle will refer to this */
|
||||
no_kill =
|
||||
fullcolormask &&
|
||||
!key->stencil[0].enabled &&
|
||||
!key->alpha.enabled &&
|
||||
@@ -3546,13 +3569,82 @@ generate_variant(struct llvmpipe_context *lp,
|
||||
!key->blend.alpha_to_coverage &&
|
||||
!key->depth.enabled &&
|
||||
!shader->info.base.uses_kill &&
|
||||
!shader->info.base.writes_samplemask
|
||||
? TRUE : FALSE;
|
||||
!shader->info.base.writes_samplemask;
|
||||
|
||||
variant->opaque =
|
||||
no_kill &&
|
||||
!key->blend.logicop_enable &&
|
||||
!key->blend.rt[0].blend_enable
|
||||
? TRUE : FALSE;
|
||||
|
||||
variant->potentially_opaque =
|
||||
no_kill &&
|
||||
!key->blend.logicop_enable &&
|
||||
key->blend.rt[0].blend_enable &&
|
||||
key->blend.rt[0].rgb_func == PIPE_BLEND_ADD &&
|
||||
key->blend.rt[0].rgb_dst_factor == PIPE_BLENDFACTOR_INV_SRC_ALPHA &&
|
||||
key->blend.rt[0].alpha_func == key->blend.rt[0].rgb_func &&
|
||||
key->blend.rt[0].alpha_dst_factor == key->blend.rt[0].rgb_dst_factor &&
|
||||
shader->base.type == PIPE_SHADER_IR_TGSI &&
|
||||
/*
|
||||
* FIXME: for NIR, all of the fields of info.xxx (except info.base)
|
||||
* are zeros, hence shader analysis (here and elsewhere) using these
|
||||
* bits cannot work and will silently fail (cbuf is the only pointer
|
||||
* field, hence causing a crash).
|
||||
*/
|
||||
shader->info.cbuf[0][3].file != TGSI_FILE_NULL
|
||||
? TRUE : FALSE;
|
||||
|
||||
/* We only care about opaque blits for now */
|
||||
if (variant->opaque &&
|
||||
(shader->kind == LP_FS_KIND_BLIT_RGBA ||
|
||||
shader->kind == LP_FS_KIND_BLIT_RGB1)) {
|
||||
unsigned target, min_img_filter, mag_img_filter, min_mip_filter;
|
||||
enum pipe_format texture_format;
|
||||
|
||||
texture_format = key->samplers[0].texture_state.format;
|
||||
target = key->samplers[0].texture_state.target;
|
||||
min_img_filter = key->samplers[0].sampler_state.min_img_filter;
|
||||
mag_img_filter = key->samplers[0].sampler_state.mag_img_filter;
|
||||
if (key->samplers[0].texture_state.level_zero_only) {
|
||||
min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
|
||||
} else {
|
||||
min_mip_filter = key->samplers[0].sampler_state.min_mip_filter;
|
||||
}
|
||||
|
||||
if (target == PIPE_TEXTURE_2D &&
|
||||
min_img_filter == PIPE_TEX_FILTER_NEAREST &&
|
||||
mag_img_filter == PIPE_TEX_FILTER_NEAREST &&
|
||||
min_mip_filter == PIPE_TEX_MIPFILTER_NONE &&
|
||||
((texture_format &&
|
||||
util_is_format_compatible(util_format_description(texture_format),
|
||||
cbuf0_format_desc)) ||
|
||||
(shader->kind == LP_FS_KIND_BLIT_RGB1 &&
|
||||
(texture_format == PIPE_FORMAT_B8G8R8A8_UNORM ||
|
||||
texture_format == PIPE_FORMAT_B8G8R8X8_UNORM) &&
|
||||
(key->cbuf_format[0] == PIPE_FORMAT_B8G8R8A8_UNORM ||
|
||||
key->cbuf_format[0] == PIPE_FORMAT_B8G8R8X8_UNORM))))
|
||||
variant->blit = 1;
|
||||
}
|
||||
|
||||
|
||||
/* Whether this is a candidate for the linear path */
|
||||
linear =
|
||||
!key->stencil[0].enabled &&
|
||||
!key->depth.enabled &&
|
||||
!shader->info.base.uses_kill &&
|
||||
!key->blend.logicop_enable &&
|
||||
(key->cbuf_format[0] == PIPE_FORMAT_B8G8R8A8_UNORM ||
|
||||
key->cbuf_format[0] == PIPE_FORMAT_B8G8R8X8_UNORM);
|
||||
|
||||
memcpy(&variant->key, key, sizeof *key);
|
||||
|
||||
if ((LP_DEBUG & DEBUG_FS) || (gallivm_debug & GALLIVM_DEBUG_IR)) {
|
||||
lp_debug_fs_variant(variant);
|
||||
}
|
||||
|
||||
llvmpipe_fs_variant_fastpath(variant);
|
||||
|
||||
lp_jit_init_types(variant);
|
||||
|
||||
if (variant->jit_function[RAST_EDGE_TEST] == NULL)
|
||||
@@ -3565,6 +3657,36 @@ generate_variant(struct llvmpipe_context *lp,
|
||||
}
|
||||
}
|
||||
|
||||
if (linear) {
|
||||
/* Currently keeping both the old fastpaths and new linear path
|
||||
* active. The older code is still somewhat faster for the cases
|
||||
* it covers.
|
||||
*
|
||||
* XXX: consider restricting this to aero-mode only.
|
||||
*/
|
||||
if (fullcolormask &&
|
||||
!key->alpha.enabled &&
|
||||
!key->blend.alpha_to_coverage) {
|
||||
llvmpipe_fs_variant_linear_fastpath(variant);
|
||||
}
|
||||
|
||||
/* If the original fastpath doesn't cover this variant, try the new
|
||||
* code:
|
||||
*/
|
||||
if (variant->jit_linear == NULL) {
|
||||
if (shader->kind == LP_FS_KIND_BLIT_RGBA ||
|
||||
shader->kind == LP_FS_KIND_BLIT_RGB1 ||
|
||||
shader->kind == LP_FS_KIND_LLVM_LINEAR) {
|
||||
llvmpipe_fs_variant_linear_llvm(lp, shader, variant);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (LP_DEBUG & DEBUG_LINEAR) {
|
||||
lp_debug_fs_variant(variant);
|
||||
debug_printf(" ----> no linear path for this variant\n");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Compile everything
|
||||
*/
|
||||
@@ -3587,6 +3709,19 @@ generate_variant(struct llvmpipe_context *lp,
|
||||
variant->jit_function[RAST_WHOLE] = variant->jit_function[RAST_EDGE_TEST];
|
||||
}
|
||||
|
||||
if (linear) {
|
||||
if (variant->linear_function) {
|
||||
variant->jit_linear_llvm = (lp_jit_linear_llvm_func)
|
||||
gallivm_jit_function(variant->gallivm, variant->linear_function);
|
||||
}
|
||||
|
||||
/*
|
||||
* This must be done after LLVM compilation, as it will call the JIT'ed
|
||||
* code to determine active inputs.
|
||||
*/
|
||||
lp_linear_check_variant(variant);
|
||||
}
|
||||
|
||||
if (needs_caching) {
|
||||
lp_disk_cache_insert_shader(screen, &cached, ir_sha1_cache_key);
|
||||
}
|
||||
@@ -3697,6 +3832,9 @@ llvmpipe_create_fs_state(struct pipe_context *pipe,
|
||||
debug_printf("\n");
|
||||
}
|
||||
|
||||
/* This will put a derived copy of the tokens into shader->base.tokens */
|
||||
llvmpipe_fs_analyse(shader, templ->tokens);
|
||||
|
||||
return shader;
|
||||
}
|
||||
|
||||
@@ -4155,11 +4293,16 @@ make_variant_key(struct llvmpipe_context *lp,
|
||||
&lp->images[PIPE_SHADER_FRAGMENT][i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (shader->kind == LP_FS_KIND_AERO_MINIFICATION) {
|
||||
key->samplers[0].sampler_state.min_img_filter = PIPE_TEX_FILTER_NEAREST;
|
||||
key->samplers[0].sampler_state.mag_img_filter = PIPE_TEX_FILTER_NEAREST;
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Update fragment shader state. This is called just prior to drawing
|
||||
* something when some fragment-related state has changed.
|
||||
|
||||
@@ -48,6 +48,16 @@ struct lp_fragment_shader;
|
||||
#define RAST_EDGE_TEST 1
|
||||
|
||||
|
||||
enum lp_fs_kind
|
||||
{
|
||||
LP_FS_KIND_GENERAL = 0,
|
||||
LP_FS_KIND_BLIT_RGBA,
|
||||
LP_FS_KIND_BLIT_RGB1,
|
||||
LP_FS_KIND_AERO_MINIFICATION,
|
||||
LP_FS_KIND_LLVM_LINEAR
|
||||
};
|
||||
|
||||
|
||||
struct lp_sampler_static_state
|
||||
{
|
||||
/*
|
||||
@@ -137,6 +147,13 @@ struct lp_fs_variant_list_item
|
||||
|
||||
struct lp_fragment_shader_variant
|
||||
{
|
||||
/*
|
||||
* Whether some primitives can be opaque.
|
||||
*/
|
||||
unsigned potentially_opaque:1;
|
||||
|
||||
unsigned blit:1;
|
||||
unsigned linear_input_mask:16;
|
||||
struct pipe_reference reference;
|
||||
boolean opaque;
|
||||
|
||||
@@ -150,6 +167,17 @@ struct lp_fragment_shader_variant
|
||||
|
||||
lp_jit_frag_func jit_function[2];
|
||||
|
||||
lp_jit_linear_func jit_linear;
|
||||
lp_jit_linear_func jit_linear_blit;
|
||||
|
||||
/* Functions within the linear path:
|
||||
*/
|
||||
LLVMValueRef linear_function;
|
||||
lp_jit_linear_llvm_func jit_linear_llvm;
|
||||
|
||||
/* Bitmask to say what cbufs are unswizzled */
|
||||
unsigned unswizzled_cbufs;
|
||||
|
||||
/* Total number of LLVM instructions generated */
|
||||
unsigned nr_instrs;
|
||||
|
||||
@@ -172,6 +200,13 @@ struct lp_fragment_shader
|
||||
struct pipe_reference reference;
|
||||
struct lp_tgsi_info info;
|
||||
|
||||
/*
|
||||
* Analysis results
|
||||
*/
|
||||
|
||||
enum lp_fs_kind kind;
|
||||
|
||||
|
||||
struct lp_fs_variant_list_item variants;
|
||||
|
||||
struct draw_fragment_shader *draw_data;
|
||||
@@ -187,9 +222,31 @@ struct lp_fragment_shader
|
||||
};
|
||||
|
||||
|
||||
void
|
||||
llvmpipe_fs_analyse(struct lp_fragment_shader *shader,
|
||||
const struct tgsi_token *tokens);
|
||||
|
||||
void
|
||||
llvmpipe_fs_variant_fastpath(struct lp_fragment_shader_variant *variant);
|
||||
|
||||
void
|
||||
llvmpipe_fs_variant_linear_fastpath(struct lp_fragment_shader_variant *variant);
|
||||
|
||||
void
|
||||
llvmpipe_fs_variant_linear_llvm(struct llvmpipe_context *lp,
|
||||
struct lp_fragment_shader *shader,
|
||||
struct lp_fragment_shader_variant *variant);
|
||||
|
||||
void
|
||||
lp_debug_fs_variant(struct lp_fragment_shader_variant *variant);
|
||||
|
||||
const char *
|
||||
lp_debug_fs_kind(enum lp_fs_kind kind);
|
||||
|
||||
|
||||
void
|
||||
lp_linear_check_variant(struct lp_fragment_shader_variant *variant);
|
||||
|
||||
void
|
||||
llvmpipe_destroy_fs(struct llvmpipe_context *llvmpipe,
|
||||
struct lp_fragment_shader *shader);
|
||||
|
||||
@@ -0,0 +1,204 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright 2010-2021 VMware, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sub license, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
* USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the
|
||||
* next paragraph) shall be included in all copies or substantial portions
|
||||
* of the Software.
|
||||
*
|
||||
**************************************************************************/
|
||||
|
||||
|
||||
#include "util/u_memory.h"
|
||||
#include "util/u_math.h"
|
||||
#include "tgsi/tgsi_parse.h"
|
||||
#include "tgsi/tgsi_text.h"
|
||||
#include "tgsi/tgsi_util.h"
|
||||
#include "tgsi/tgsi_dump.h"
|
||||
#include "lp_debug.h"
|
||||
#include "lp_state.h"
|
||||
|
||||
|
||||
/*
|
||||
* Detect Aero minification shaders.
|
||||
*
|
||||
* Aero does not use texture mimaps when a window gets animated and its shaped
|
||||
* bended. Instead it uses the average of 4 nearby texels. This is the simplest
|
||||
* of such shader, but there are several variations:
|
||||
*
|
||||
* FRAG
|
||||
* DCL IN[0], GENERIC[1], PERSPECTIVE
|
||||
* DCL IN[1], GENERIC[2], PERSPECTIVE
|
||||
* DCL IN[2], GENERIC[3], PERSPECTIVE
|
||||
* DCL OUT[0], COLOR
|
||||
* DCL SAMP[0]
|
||||
* DCL TEMP[0..3]
|
||||
* IMM FLT32 { 0.2500, 0.0000, 0.0000, 0.0000 }
|
||||
* MOV TEMP[0].x, IN[0].zzzz
|
||||
* MOV TEMP[0].y, IN[0].wwww
|
||||
* MOV TEMP[1].x, IN[1].zzzz
|
||||
* MOV TEMP[1].y, IN[1].wwww
|
||||
* TEX TEMP[0], TEMP[0], SAMP[0], 2D
|
||||
* TEX TEMP[2], IN[0], SAMP[0], 2D
|
||||
* TEX TEMP[3], IN[1], SAMP[0], 2D
|
||||
* TEX TEMP[1], TEMP[1], SAMP[0], 2D
|
||||
* ADD TEMP[0], TEMP[0], TEMP[2]
|
||||
* ADD TEMP[0], TEMP[3], TEMP[0]
|
||||
* ADD TEMP[0], TEMP[1], TEMP[0]
|
||||
* MUL TEMP[0], TEMP[0], IN[2]
|
||||
* MUL TEMP[0], TEMP[0], IMM[0].xxxx
|
||||
* MOV OUT[0], TEMP[0]
|
||||
* END
|
||||
*
|
||||
* Texture coordinates are interleaved like the Gaussian blur shaders, but
|
||||
* unlike the later there isn't structure in the sub-pixel positioning of the
|
||||
* texels, other than being disposed in a diamond-like shape. For example,
|
||||
* these are the relative offsets of the texels relative to the average:
|
||||
*
|
||||
* x offset y offset
|
||||
* --------------------
|
||||
* 0.691834 -0.21360
|
||||
* -0.230230 -0.64160
|
||||
* -0.692406 0.21356
|
||||
* 0.230802 0.64160
|
||||
*
|
||||
* These shaders are typically used with linear min/mag filtering, but the
|
||||
* linear filtering provides very little visual improvement compared to the
|
||||
* performance impact it has. The ultimate purpose of detecting these shaders
|
||||
* is to override with nearest texture filtering.
|
||||
*/
|
||||
static inline boolean
|
||||
match_aero_minification_shader(const struct tgsi_token *tokens,
|
||||
const struct lp_tgsi_info *info)
|
||||
{
|
||||
struct tgsi_parse_context parse;
|
||||
unsigned coord_mask;
|
||||
boolean has_quarter_imm;
|
||||
unsigned index, chan;
|
||||
|
||||
if ((info->base.opcode_count[TGSI_OPCODE_TEX] != 4 &&
|
||||
info->base.opcode_count[TGSI_OPCODE_SAMPLE] != 4) ||
|
||||
info->num_texs != 4) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ensure the texture coordinates are interleaved as in the example above.
|
||||
*/
|
||||
|
||||
coord_mask = 0;
|
||||
for (index = 0; index < 4; ++index) {
|
||||
const struct lp_tgsi_texture_info *tex = &info->tex[index];
|
||||
if (tex->sampler_unit != 0 ||
|
||||
tex->texture_unit != 0 ||
|
||||
tex->coord[0].file != TGSI_FILE_INPUT ||
|
||||
tex->coord[1].file != TGSI_FILE_INPUT ||
|
||||
tex->coord[0].u.index != tex->coord[1].u.index ||
|
||||
(tex->coord[0].swizzle % 2) != 0 ||
|
||||
tex->coord[1].swizzle != tex->coord[0].swizzle + 1) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
coord_mask |= 1 << (tex->coord[0].u.index*2 + tex->coord[0].swizzle/2);
|
||||
}
|
||||
if (coord_mask != 0xf) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ensure it has the 0.25 immediate.
|
||||
*/
|
||||
|
||||
has_quarter_imm = FALSE;
|
||||
|
||||
tgsi_parse_init(&parse, tokens);
|
||||
|
||||
while (!tgsi_parse_end_of_tokens(&parse)) {
|
||||
tgsi_parse_token(&parse);
|
||||
|
||||
switch (parse.FullToken.Token.Type) {
|
||||
case TGSI_TOKEN_TYPE_DECLARATION:
|
||||
break;
|
||||
|
||||
case TGSI_TOKEN_TYPE_INSTRUCTION:
|
||||
goto finished;
|
||||
|
||||
case TGSI_TOKEN_TYPE_IMMEDIATE:
|
||||
{
|
||||
const unsigned size =
|
||||
parse.FullToken.FullImmediate.Immediate.NrTokens - 1;
|
||||
assert(size <= 4);
|
||||
for (chan = 0; chan < size; ++chan) {
|
||||
if (parse.FullToken.FullImmediate.u[chan].Float == 0.25f) {
|
||||
has_quarter_imm = TRUE;
|
||||
goto finished;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TGSI_TOKEN_TYPE_PROPERTY:
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
goto finished;
|
||||
}
|
||||
}
|
||||
finished:
|
||||
|
||||
tgsi_parse_free(&parse);
|
||||
|
||||
if (!has_quarter_imm) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
llvmpipe_fs_analyse(struct lp_fragment_shader *shader,
|
||||
const struct tgsi_token *tokens)
|
||||
{
|
||||
shader->kind = LP_FS_KIND_GENERAL;
|
||||
|
||||
if (shader->kind == LP_FS_KIND_GENERAL &&
|
||||
shader->info.base.num_inputs <= LP_MAX_LINEAR_INPUTS &&
|
||||
shader->info.base.num_outputs == 1 &&
|
||||
!shader->info.indirect_textures &&
|
||||
!shader->info.sampler_texture_units_different &&
|
||||
!shader->info.unclamped_immediates &&
|
||||
shader->info.num_texs <= LP_MAX_LINEAR_TEXTURES &&
|
||||
(shader->info.base.opcode_count[TGSI_OPCODE_TEX] +
|
||||
shader->info.base.opcode_count[TGSI_OPCODE_SAMPLE] +
|
||||
shader->info.base.opcode_count[TGSI_OPCODE_MOV] +
|
||||
shader->info.base.opcode_count[TGSI_OPCODE_MUL] +
|
||||
shader->info.base.opcode_count[TGSI_OPCODE_RET] +
|
||||
shader->info.base.opcode_count[TGSI_OPCODE_END] ==
|
||||
shader->info.base.num_instructions)) {
|
||||
shader->kind = LP_FS_KIND_LLVM_LINEAR;
|
||||
}
|
||||
|
||||
if (shader->kind == LP_FS_KIND_GENERAL &&
|
||||
match_aero_minification_shader(tokens, &shader->info)) {
|
||||
shader->kind = LP_FS_KIND_AERO_MINIFICATION;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,238 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright 2010-2021 VMware, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sub license, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
* USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the
|
||||
* next paragraph) shall be included in all copies or substantial portions
|
||||
* of the Software.
|
||||
*
|
||||
**************************************************************************/
|
||||
|
||||
|
||||
#include "pipe/p_config.h"
|
||||
|
||||
#include "util/u_math.h"
|
||||
#include "util/u_cpu_detect.h"
|
||||
#include "util/u_sse.h"
|
||||
|
||||
#include "lp_jit.h"
|
||||
#include "lp_state_fs.h"
|
||||
#include "lp_debug.h"
|
||||
|
||||
|
||||
#if defined(PIPE_ARCH_SSE)
|
||||
|
||||
#include <emmintrin.h>
|
||||
|
||||
|
||||
static void
|
||||
no_op(const struct lp_jit_context *context,
|
||||
uint32_t x,
|
||||
uint32_t y,
|
||||
uint32_t facing,
|
||||
const void *a0,
|
||||
const void *dadx,
|
||||
const void *dady,
|
||||
uint8_t **cbufs,
|
||||
uint8_t *depth,
|
||||
uint64_t mask,
|
||||
struct lp_jit_thread_data *thread_data,
|
||||
unsigned *strides,
|
||||
unsigned depth_stride,
|
||||
unsigned *color_sample_stride,
|
||||
unsigned depth_sample_stride)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* m ? a : b
|
||||
*/
|
||||
static inline __m128i
|
||||
mm_select_si128(__m128i m, __m128i a, __m128i b)
|
||||
{
|
||||
__m128i res;
|
||||
|
||||
/*
|
||||
* TODO: use PBLENVB when available.
|
||||
*/
|
||||
|
||||
res = _mm_or_si128(_mm_and_si128(m, a),
|
||||
_mm_andnot_si128(m, b));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* *p = m ? a : *p;
|
||||
*/
|
||||
static inline void
|
||||
mm_store_mask_si128(__m128i *p, __m128i m, __m128i a)
|
||||
{
|
||||
_mm_store_si128(p, mm_select_si128(m, a, _mm_load_si128(p)));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Expand the mask from a 16 bit integer to a 4 x 4 x 32 bit vector mask, ie.
|
||||
* 1 bit -> 32bits.
|
||||
*/
|
||||
static inline void
|
||||
expand_mask(uint32_t int_mask,
|
||||
__m128i *vec_mask)
|
||||
{
|
||||
__m128i inv_mask = _mm_set1_epi32(~int_mask & 0xffff);
|
||||
__m128i zero = _mm_setzero_si128();
|
||||
|
||||
vec_mask[0] = _mm_and_si128(inv_mask, _mm_setr_epi32(0x0001, 0x0002, 0x0004, 0x0008));
|
||||
vec_mask[1] = _mm_and_si128(inv_mask, _mm_setr_epi32(0x0010, 0x0020, 0x0040, 0x0080));
|
||||
inv_mask = _mm_srli_epi32(inv_mask, 8);
|
||||
vec_mask[2] = _mm_and_si128(inv_mask, _mm_setr_epi32(0x0001, 0x0002, 0x0004, 0x0008));
|
||||
vec_mask[3] = _mm_and_si128(inv_mask, _mm_setr_epi32(0x0010, 0x0020, 0x0040, 0x0080));
|
||||
|
||||
vec_mask[0] = _mm_cmpeq_epi32(vec_mask[0], zero);
|
||||
vec_mask[1] = _mm_cmpeq_epi32(vec_mask[1], zero);
|
||||
vec_mask[2] = _mm_cmpeq_epi32(vec_mask[2], zero);
|
||||
vec_mask[3] = _mm_cmpeq_epi32(vec_mask[3], zero);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Draw opaque color (for debugging).
|
||||
*/
|
||||
static void
|
||||
opaque_color(uint8_t **cbufs, unsigned *strides,
|
||||
uint32_t int_mask,
|
||||
uint32_t color)
|
||||
{
|
||||
__m128i *cbuf = (__m128i *)cbufs[0];
|
||||
unsigned stride = strides[0] / sizeof *cbuf;
|
||||
__m128i vec_mask[4];
|
||||
__m128i vec_color = _mm_set1_epi32(color);
|
||||
|
||||
expand_mask(int_mask, vec_mask);
|
||||
|
||||
mm_store_mask_si128(cbuf, vec_mask[0], vec_color); cbuf += stride;
|
||||
mm_store_mask_si128(cbuf, vec_mask[1], vec_color); cbuf += stride;
|
||||
mm_store_mask_si128(cbuf, vec_mask[2], vec_color); cbuf += stride;
|
||||
mm_store_mask_si128(cbuf, vec_mask[3], vec_color);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Draw opaque red (for debugging).
|
||||
*/
|
||||
static void
|
||||
red(const struct lp_jit_context *context,
|
||||
uint32_t x,
|
||||
uint32_t y,
|
||||
uint32_t facing,
|
||||
const void *a0,
|
||||
const void *dadx,
|
||||
const void *dady,
|
||||
uint8_t **cbufs,
|
||||
uint8_t *depth,
|
||||
uint64_t int_mask,
|
||||
struct lp_jit_thread_data *thread_data,
|
||||
unsigned *strides,
|
||||
unsigned depth_stride,
|
||||
unsigned *sample_stride,
|
||||
unsigned depth_sample_stride)
|
||||
{
|
||||
opaque_color(cbufs, strides, int_mask, 0xffff0000);
|
||||
(void)facing;
|
||||
(void)depth;
|
||||
(void)thread_data;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Draw opaque green (for debugging).
|
||||
*/
|
||||
static void
|
||||
green(const struct lp_jit_context *context,
|
||||
uint32_t x,
|
||||
uint32_t y,
|
||||
uint32_t facing,
|
||||
const void *a0,
|
||||
const void *dadx,
|
||||
const void *dady,
|
||||
uint8_t **cbufs,
|
||||
uint8_t *depth,
|
||||
uint64_t int_mask,
|
||||
struct lp_jit_thread_data *thread_data,
|
||||
unsigned *strides,
|
||||
unsigned depth_stride,
|
||||
unsigned *sample_stride,
|
||||
unsigned depth_sample_stride)
|
||||
{
|
||||
opaque_color(cbufs, strides, int_mask, 0xff00ff00);
|
||||
(void)facing;
|
||||
(void)depth;
|
||||
(void)thread_data;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
llvmpipe_fs_variant_fastpath(struct lp_fragment_shader_variant *variant)
|
||||
{
|
||||
variant->jit_function[RAST_WHOLE] = NULL;
|
||||
variant->jit_function[RAST_EDGE_TEST] = NULL;
|
||||
|
||||
if (LP_DEBUG & DEBUG_NO_FASTPATH)
|
||||
return;
|
||||
|
||||
if (variant->key.cbuf_format[0] != PIPE_FORMAT_B8G8R8A8_UNORM &&
|
||||
variant->key.cbuf_format[0] != PIPE_FORMAT_B8G8R8X8_UNORM) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (0) {
|
||||
variant->jit_function[RAST_WHOLE] = red;
|
||||
variant->jit_function[RAST_EDGE_TEST] = red;
|
||||
}
|
||||
|
||||
if (0) {
|
||||
variant->jit_function[RAST_WHOLE] = green;
|
||||
variant->jit_function[RAST_EDGE_TEST] = green;
|
||||
}
|
||||
|
||||
if (0) {
|
||||
variant->jit_function[RAST_WHOLE] = no_op;
|
||||
variant->jit_function[RAST_EDGE_TEST] = no_op;
|
||||
}
|
||||
|
||||
/* Make it easier to see triangles:
|
||||
*/
|
||||
if ((LP_DEBUG & DEBUG_LINEAR) || (LP_PERF & PERF_NO_SHADE)) {
|
||||
variant->jit_function[RAST_EDGE_TEST] = red;
|
||||
variant->jit_function[RAST_WHOLE] = green;
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void
|
||||
llvmpipe_fs_variant_fastpath(struct lp_fragment_shader_variant *variant)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,713 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright 2010-2021 VMware, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sub license, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
* USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the
|
||||
* next paragraph) shall be included in all copies or substantial portions
|
||||
* of the Software.
|
||||
*
|
||||
**************************************************************************/
|
||||
|
||||
|
||||
#include "pipe/p_config.h"
|
||||
|
||||
#include "util/u_math.h"
|
||||
#include "util/u_cpu_detect.h"
|
||||
#include "util/u_pack_color.h"
|
||||
#include "util/u_surface.h"
|
||||
#include "util/u_sse.h"
|
||||
|
||||
#include "lp_jit.h"
|
||||
#include "lp_rast.h"
|
||||
#include "lp_debug.h"
|
||||
#include "lp_state_fs.h"
|
||||
#include "lp_linear_priv.h"
|
||||
|
||||
|
||||
#if defined(PIPE_ARCH_SSE)
|
||||
|
||||
#include <emmintrin.h>
|
||||
|
||||
|
||||
struct nearest_sampler {
|
||||
PIPE_ALIGN_VAR(16) uint32_t out[64];
|
||||
|
||||
const struct lp_jit_texture *texture;
|
||||
float fsrc_x; /* src_x0 */
|
||||
float fsrc_y; /* src_y0 */
|
||||
float fdsdx; /* sx */
|
||||
float fdsdy; /* sx */
|
||||
float fdtdx; /* sy */
|
||||
float fdtdy; /* sy */
|
||||
int width;
|
||||
int y;
|
||||
|
||||
const uint32_t *(*fetch)(struct nearest_sampler *samp);
|
||||
};
|
||||
|
||||
|
||||
struct linear_interp {
|
||||
PIPE_ALIGN_VAR(16) uint32_t out[64];
|
||||
__m128i a0;
|
||||
__m128i dadx;
|
||||
__m128i dady;
|
||||
int width; /* rounded up to multiple of 4 */
|
||||
boolean is_constant;
|
||||
};
|
||||
|
||||
/* Organize all the information needed for blending in one place.
|
||||
* Could have blend function pointer here, but we currently always
|
||||
* know which one we want to call.
|
||||
*/
|
||||
struct color_blend {
|
||||
const uint32_t *src;
|
||||
uint8_t *color;
|
||||
int stride;
|
||||
int width; /* the exact width */
|
||||
};
|
||||
|
||||
|
||||
/* Organize all the information needed for running each of the shaders
|
||||
* in one place.
|
||||
*/
|
||||
struct shader {
|
||||
PIPE_ALIGN_VAR(16) uint32_t out0[64];
|
||||
const uint32_t *src0;
|
||||
const uint32_t *src1;
|
||||
__m128i const0;
|
||||
int width; /* rounded up to multiple of 4 */
|
||||
};
|
||||
|
||||
|
||||
/* For a row of pixels, perform add/one/inv_src_alpha (ie
|
||||
* premultiplied alpha) blending between the incoming pixels and the
|
||||
* destination buffer.
|
||||
*
|
||||
* Used to implement the BLIT_RGBA + blend shader, there are no
|
||||
* operations from the pixel shader left to implement at this level -
|
||||
* effectively the pixel shader was just a texture fetch which has
|
||||
* already been performed. This routine then purely implements
|
||||
* blending.
|
||||
*/
|
||||
static void
|
||||
blend_premul(struct color_blend *blend)
|
||||
{
|
||||
const uint32_t *src = blend->src; /* aligned */
|
||||
uint32_t *dst = (uint32_t *)blend->color; /* unaligned */
|
||||
int width = blend->width;
|
||||
int i;
|
||||
__m128i tmp;
|
||||
union { __m128i m128; uint ui[4]; } dstreg;
|
||||
|
||||
blend->color += blend->stride;
|
||||
|
||||
for (i = 0; i + 3 < width; i += 4) {
|
||||
tmp = _mm_loadu_si128((const __m128i *)&dst[i]); /* UNALIGNED READ */
|
||||
dstreg.m128 = util_sse2_blend_premul_4(*(const __m128i *)&src[i],
|
||||
tmp);
|
||||
_mm_storeu_si128((__m128i *)&dst[i], dstreg.m128); /* UNALIGNED WRITE */
|
||||
}
|
||||
|
||||
if (i < width) {
|
||||
int j;
|
||||
for (j = 0; j < width - i ; j++) {
|
||||
dstreg.ui[j] = dst[i+j];
|
||||
}
|
||||
dstreg.m128 = util_sse2_blend_premul_4(*(const __m128i *)&src[i],
|
||||
dstreg.m128);
|
||||
for (; i < width; i++)
|
||||
dst[i] = dstreg.ui[i&3];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
blend_noop(struct color_blend *blend)
|
||||
{
|
||||
memcpy(blend->color, blend->src, blend->width * sizeof(unsigned));
|
||||
blend->color += blend->stride;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
init_blend(struct color_blend *blend,
|
||||
int x, int y, int width, int height,
|
||||
uint8_t *color,
|
||||
int stride)
|
||||
{
|
||||
blend->color = color + x * 4 + y * stride;
|
||||
blend->stride = stride;
|
||||
blend->width = width;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Perform nearest filtered lookup of a row of texels. Texture lookup
|
||||
* is assumed to be axis aligned but with arbitrary scaling.
|
||||
*
|
||||
* Texture coordinate interpolation is performed in 24.8 fixed point.
|
||||
* Note that the longest span we will encounter is 64 pixels long,
|
||||
* meaning that 8 fractional bits is more than sufficient to represent
|
||||
* the shallowest gradient possible within this span.
|
||||
*
|
||||
* After 64 pixels (ie. in the next tile), the starting point will be
|
||||
* recalculated with floating point arithmetic.
|
||||
*
|
||||
* XXX: migrate this to use Jose's quad blitter texture fetch routines.
|
||||
*/
|
||||
static const uint32_t *
|
||||
fetch_row(struct nearest_sampler *samp)
|
||||
{
|
||||
int y = samp->y++;
|
||||
uint32_t *row = samp->out;
|
||||
const struct lp_jit_texture *texture = samp->texture;
|
||||
int yy = util_iround(samp->fsrc_y + samp->fdtdy * y);
|
||||
const uint32_t *src_row =
|
||||
(const uint32_t *)((const uint8_t *)texture->base +
|
||||
yy * texture->row_stride[0]);
|
||||
int iscale_x = samp->fdsdx * 256;
|
||||
int acc = samp->fsrc_x * 256 + 128;
|
||||
int width = samp->width;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < width; i++) {
|
||||
row[i] = src_row[acc>>8];
|
||||
acc += iscale_x;
|
||||
}
|
||||
|
||||
return row;
|
||||
}
|
||||
|
||||
/* Version of fetch_row which can cope with texture edges. In
|
||||
* practise, aero never triggers this.
|
||||
*/
|
||||
static const uint32_t *
|
||||
fetch_row_clamped(struct nearest_sampler *samp)
|
||||
{
|
||||
int y = samp->y++;
|
||||
uint32_t *row = samp->out;
|
||||
const struct lp_jit_texture *texture = samp->texture;
|
||||
|
||||
int yy = util_iround(samp->fsrc_y + samp->fdtdy * y);
|
||||
|
||||
const uint32_t *src_row =
|
||||
(const uint32_t *)((const uint8_t *)texture->base +
|
||||
CLAMP(yy, 0, texture->height-1) *
|
||||
texture->row_stride[0]);
|
||||
float src_x0 = samp->fsrc_x;
|
||||
float scale_x = samp->fdsdx;
|
||||
int width = samp->width;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < width; i++) {
|
||||
row[i] = src_row[CLAMP(util_iround(src_x0 + i*scale_x),0,texture->width-1)];
|
||||
}
|
||||
|
||||
return row;
|
||||
}
|
||||
|
||||
/* It vary rarely happens that some non-axis-aligned texturing creeps
|
||||
* into the linear path. Handle it here. The alternative would be
|
||||
* more pre-checking or an option to fallback by returning false from
|
||||
* jit_linear.
|
||||
*/
|
||||
static const uint32_t *
|
||||
fetch_row_xy_clamped(struct nearest_sampler *samp)
|
||||
{
|
||||
int y = samp->y++;
|
||||
uint32_t *row = samp->out;
|
||||
const struct lp_jit_texture *texture = samp->texture;
|
||||
float yrow = samp->fsrc_y + samp->fdtdy * y;
|
||||
float xrow = samp->fsrc_x + samp->fdsdy * y;
|
||||
int width = samp->width;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < width; i++) {
|
||||
int yy = util_iround(yrow + samp->fdtdx * i);
|
||||
int xx = util_iround(xrow + samp->fdsdx * i);
|
||||
|
||||
const uint32_t *src_row =
|
||||
(const uint32_t *)((const uint8_t *)texture->base +
|
||||
CLAMP(yy, 0, texture->height-1) *
|
||||
texture->row_stride[0]);
|
||||
|
||||
row[i] = src_row[CLAMP(xx,0,texture->width-1)];
|
||||
}
|
||||
|
||||
return row;
|
||||
}
|
||||
|
||||
|
||||
static boolean
|
||||
init_nearest_sampler(struct nearest_sampler *samp,
|
||||
const struct lp_jit_texture *texture,
|
||||
int x0, int y0,
|
||||
int width, int height,
|
||||
float s0, float dsdx, float dsdy,
|
||||
float t0, float dtdx, float dtdy,
|
||||
float w0, float dwdx, float dwdy)
|
||||
{
|
||||
int i;
|
||||
float oow = 1.0f / w0;
|
||||
|
||||
if (dwdx != 0.0 || dwdy != 0.0)
|
||||
return FALSE;
|
||||
|
||||
samp->texture = texture;
|
||||
samp->width = width;
|
||||
samp->fdsdx = dsdx * texture->width * oow;
|
||||
samp->fdsdy = dsdy * texture->width * oow;
|
||||
samp->fdtdx = dtdx * texture->height * oow;
|
||||
samp->fdtdy = dtdy * texture->height * oow;
|
||||
samp->fsrc_x = (samp->fdsdx * x0 +
|
||||
samp->fdsdy * y0 +
|
||||
s0 * texture->width * oow - 0.5f);
|
||||
|
||||
samp->fsrc_y = (samp->fdtdx * x0 +
|
||||
samp->fdtdy * y0 +
|
||||
t0 * texture->height * oow - 0.5f);
|
||||
samp->y = 0;
|
||||
|
||||
/* Because we want to permit consumers of this data to round up to
|
||||
* the next multiple of 4, and because we don't want valgrind to
|
||||
* complain about uninitialized reads, set the last bit of the
|
||||
* buffer to zero:
|
||||
*/
|
||||
for (i = width; i & 3; i++)
|
||||
samp->out[i] = 0;
|
||||
|
||||
if (dsdy != 0 || dtdx != 0)
|
||||
{
|
||||
/* Arbitrary texture lookup:
|
||||
*/
|
||||
samp->fetch = fetch_row_xy_clamped;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Axis aligned stretch blit, abitrary scaling factors including
|
||||
* flipped, minifying and magnifying:
|
||||
*/
|
||||
int isrc_x = util_iround(samp->fsrc_x);
|
||||
int isrc_y = util_iround(samp->fsrc_y);
|
||||
int isrc_x1 = util_iround(samp->fsrc_x + width * samp->fdsdx);
|
||||
int isrc_y1 = util_iround(samp->fsrc_y + height * samp->fdtdy);
|
||||
|
||||
/* Look at the maximum and minimum texture coordinates we will be
|
||||
* fetching and figure out if we need to use clamping. There is
|
||||
* similar code in u_blit_sw.c which takes a better approach to
|
||||
* this which could be substituted later.
|
||||
*/
|
||||
if (isrc_x <= texture->width && isrc_x >= 0 &&
|
||||
isrc_y <= texture->height && isrc_y >= 0 &&
|
||||
isrc_x1 <= texture->width && isrc_x1 >= 0 &&
|
||||
isrc_y1 <= texture->height && isrc_y1 >= 0)
|
||||
{
|
||||
samp->fetch = fetch_row;
|
||||
}
|
||||
else {
|
||||
samp->fetch = fetch_row_clamped;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static const uint32_t *
|
||||
shade_rgb1(struct shader *shader)
|
||||
{
|
||||
const __m128i rgb1 = _mm_set1_epi32(0xff000000);
|
||||
const uint32_t *src0 = shader->src0;
|
||||
uint32_t *dst = shader->out0;
|
||||
int width = shader->width;
|
||||
int i;
|
||||
|
||||
for (i = 0; i + 3 < width; i += 4) {
|
||||
__m128i s = *(const __m128i *)&src0[i];
|
||||
*(__m128i *)&dst[i] = _mm_or_si128(s, rgb1);
|
||||
}
|
||||
|
||||
return shader->out0;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
init_shader(struct shader *shader,
|
||||
int x, int y, int width, int height)
|
||||
{
|
||||
shader->width = align(width, 4);
|
||||
}
|
||||
|
||||
|
||||
/* Linear shader which implements the BLIT_RGBA shader with the
|
||||
* additional constraints imposed by lp_setup_is_blit().
|
||||
*/
|
||||
static boolean
|
||||
blit_rgba_blit(const struct lp_rast_state *state,
|
||||
unsigned x, unsigned y,
|
||||
unsigned width, unsigned height,
|
||||
const float (*a0)[4],
|
||||
const float (*dadx)[4],
|
||||
const float (*dady)[4],
|
||||
uint8_t *color,
|
||||
unsigned stride)
|
||||
{
|
||||
const struct lp_jit_context *context = &state->jit_context;
|
||||
const struct lp_jit_texture *texture = &context->textures[0];
|
||||
const uint8_t *src;
|
||||
unsigned src_stride;
|
||||
int src_x, src_y;
|
||||
|
||||
LP_DBG(DEBUG_RAST, "%s\n", __FUNCTION__);
|
||||
|
||||
/* Require w==1.0:
|
||||
*/
|
||||
if (a0[0][3] != 1.0 ||
|
||||
dadx[0][3] != 0.0 ||
|
||||
dady[0][3] != 0.0)
|
||||
return FALSE;
|
||||
|
||||
src_x = x + util_iround(a0[1][0]*texture->width - 0.5f);
|
||||
src_y = y + util_iround(a0[1][1]*texture->height - 0.5f);
|
||||
|
||||
src = texture->base;
|
||||
src_stride = texture->row_stride[0];
|
||||
|
||||
/* Fall back to blit_rgba() if clamping required:
|
||||
*/
|
||||
if (src_x < 0 ||
|
||||
src_y < 0 ||
|
||||
src_x + width > texture->width ||
|
||||
src_y + height > texture->height)
|
||||
return FALSE;
|
||||
|
||||
util_copy_rect(color, PIPE_FORMAT_B8G8R8A8_UNORM, stride,
|
||||
x, y,
|
||||
width, height,
|
||||
src, src_stride,
|
||||
src_x, src_y);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/* Linear shader which implements the BLIT_RGB1 shader, with the
|
||||
* additional constraints imposed by lp_setup_is_blit().
|
||||
*/
|
||||
static boolean
|
||||
blit_rgb1_blit(const struct lp_rast_state *state,
|
||||
unsigned x, unsigned y,
|
||||
unsigned width, unsigned height,
|
||||
const float (*a0)[4],
|
||||
const float (*dadx)[4],
|
||||
const float (*dady)[4],
|
||||
uint8_t *color,
|
||||
unsigned stride)
|
||||
{
|
||||
const struct lp_jit_context *context = &state->jit_context;
|
||||
const struct lp_jit_texture *texture = &context->textures[0];
|
||||
const uint8_t *src;
|
||||
unsigned src_stride;
|
||||
int src_x, src_y;
|
||||
|
||||
LP_DBG(DEBUG_RAST, "%s\n", __FUNCTION__);
|
||||
|
||||
/* Require w==1.0:
|
||||
*/
|
||||
if (a0[0][3] != 1.0 ||
|
||||
dadx[0][3] != 0.0 ||
|
||||
dady[0][3] != 0.0)
|
||||
return FALSE;
|
||||
|
||||
color += x * 4 + y * stride;
|
||||
|
||||
src_x = x + util_iround(a0[1][0]*texture->width - 0.5f);
|
||||
src_y = y + util_iround(a0[1][1]*texture->height - 0.5f);
|
||||
|
||||
src = texture->base;
|
||||
src_stride = texture->row_stride[0];
|
||||
src += src_x * 4;
|
||||
src += src_y * src_stride;
|
||||
|
||||
if (src_x < 0 ||
|
||||
src_y < 0 ||
|
||||
src_x + width > texture->width ||
|
||||
src_y + height > texture->height)
|
||||
return FALSE;
|
||||
|
||||
for (y = 0; y < height; y++) {
|
||||
const uint32_t *src_row = (const uint32_t *)src;
|
||||
uint32_t *dst_row = (uint32_t *)color;
|
||||
|
||||
for (x = 0; x < width; x++) {
|
||||
*dst_row++ = *src_row++ | 0xff000000;
|
||||
}
|
||||
|
||||
color += stride;
|
||||
src += src_stride;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/* Linear shader variant implementing the BLIT_RGBA shader without
|
||||
* blending.
|
||||
*/
|
||||
static boolean
|
||||
blit_rgba(const struct lp_rast_state *state,
|
||||
unsigned x, unsigned y,
|
||||
unsigned width, unsigned height,
|
||||
const float (*a0)[4],
|
||||
const float (*dadx)[4],
|
||||
const float (*dady)[4],
|
||||
uint8_t *color,
|
||||
unsigned stride)
|
||||
{
|
||||
const struct lp_jit_context *context = &state->jit_context;
|
||||
struct nearest_sampler samp;
|
||||
struct color_blend blend;
|
||||
|
||||
LP_DBG(DEBUG_RAST, "%s\n", __FUNCTION__);
|
||||
|
||||
if (!init_nearest_sampler(&samp,
|
||||
&context->textures[0],
|
||||
x, y, width, height,
|
||||
a0[1][0], dadx[1][0], dady[1][0],
|
||||
a0[1][1], dadx[1][1], dady[1][1],
|
||||
a0[0][3], dadx[0][3], dady[0][3]))
|
||||
return FALSE;
|
||||
|
||||
init_blend(&blend,
|
||||
x, y, width, height,
|
||||
color, stride);
|
||||
|
||||
/* Rasterize the rectangle and run the shader:
|
||||
*/
|
||||
for (y = 0; y < height; y++) {
|
||||
blend.src = samp.fetch(&samp);
|
||||
blend_noop(&blend);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static boolean
|
||||
blit_rgb1(const struct lp_rast_state *state,
|
||||
unsigned x, unsigned y,
|
||||
unsigned width, unsigned height,
|
||||
const float (*a0)[4],
|
||||
const float (*dadx)[4],
|
||||
const float (*dady)[4],
|
||||
uint8_t *color,
|
||||
unsigned stride)
|
||||
{
|
||||
const struct lp_jit_context *context = &state->jit_context;
|
||||
struct nearest_sampler samp;
|
||||
struct color_blend blend;
|
||||
struct shader shader;
|
||||
|
||||
LP_DBG(DEBUG_RAST, "%s\n", __FUNCTION__);
|
||||
|
||||
if (!init_nearest_sampler(&samp,
|
||||
&context->textures[0],
|
||||
x, y, width, height,
|
||||
a0[1][0], dadx[1][0], dady[1][0],
|
||||
a0[1][1], dadx[1][1], dady[1][1],
|
||||
a0[0][3], dadx[0][3], dady[0][3]))
|
||||
return FALSE;
|
||||
|
||||
init_blend(&blend,
|
||||
x, y, width, height,
|
||||
color, stride);
|
||||
|
||||
|
||||
init_shader(&shader,
|
||||
x, y, width, height);
|
||||
|
||||
/* Rasterize the rectangle and run the shader:
|
||||
*/
|
||||
for (y = 0; y < height; y++) {
|
||||
shader.src0 = samp.fetch(&samp);
|
||||
blend.src = shade_rgb1(&shader);
|
||||
blend_noop(&blend);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/* Linear shader variant implementing the BLIT_RGBA shader with
|
||||
* one/inv_src_alpha blending.
|
||||
*/
|
||||
static boolean
|
||||
blit_rgba_blend_premul(const struct lp_rast_state *state,
|
||||
unsigned x, unsigned y,
|
||||
unsigned width, unsigned height,
|
||||
const float (*a0)[4],
|
||||
const float (*dadx)[4],
|
||||
const float (*dady)[4],
|
||||
uint8_t *color,
|
||||
unsigned stride)
|
||||
{
|
||||
const struct lp_jit_context *context = &state->jit_context;
|
||||
struct nearest_sampler samp;
|
||||
struct color_blend blend;
|
||||
|
||||
LP_DBG(DEBUG_RAST, "%s\n", __FUNCTION__);
|
||||
|
||||
if (!init_nearest_sampler(&samp,
|
||||
&context->textures[0],
|
||||
x, y, width, height,
|
||||
a0[1][0], dadx[1][0], dady[1][0],
|
||||
a0[1][1], dadx[1][1], dady[1][1],
|
||||
a0[0][3], dadx[0][3], dady[0][3]))
|
||||
return FALSE;
|
||||
|
||||
|
||||
init_blend(&blend,
|
||||
x, y, width, height,
|
||||
color, stride);
|
||||
|
||||
/* Rasterize the rectangle and run the shader:
|
||||
*/
|
||||
for (y = 0; y < height; y++) {
|
||||
blend.src = samp.fetch(&samp);
|
||||
blend_premul(&blend);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/* Linear shader which always emits red. Used for debugging.
|
||||
*/
|
||||
static boolean
|
||||
linear_red(const struct lp_rast_state *state,
|
||||
unsigned x, unsigned y,
|
||||
unsigned width, unsigned height,
|
||||
const float (*a0)[4],
|
||||
const float (*dadx)[4],
|
||||
const float (*dady)[4],
|
||||
uint8_t *color,
|
||||
unsigned stride)
|
||||
{
|
||||
union util_color uc;
|
||||
|
||||
util_pack_color_ub(0xff, 0, 0, 0xff,
|
||||
PIPE_FORMAT_B8G8R8A8_UNORM, &uc);
|
||||
|
||||
util_fill_rect(color,
|
||||
PIPE_FORMAT_B8G8R8A8_UNORM,
|
||||
stride,
|
||||
x,
|
||||
y,
|
||||
width,
|
||||
height,
|
||||
&uc);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/* Noop linear shader variant, for debugging.
|
||||
*/
|
||||
static boolean
|
||||
linear_no_op(const struct lp_rast_state *state,
|
||||
unsigned x, unsigned y,
|
||||
unsigned width, unsigned height,
|
||||
const float (*a0)[4],
|
||||
const float (*dadx)[4],
|
||||
const float (*dady)[4],
|
||||
uint8_t *color,
|
||||
unsigned stride)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Check for ADD/ONE/INV_SRC_ALPHA, ie premultiplied-alpha blending.
|
||||
*/
|
||||
static boolean
|
||||
is_one_inv_src_alpha_blend(const struct lp_fragment_shader_variant *variant)
|
||||
{
|
||||
return
|
||||
!variant->key.blend.logicop_enable &&
|
||||
variant->key.blend.rt[0].blend_enable &&
|
||||
variant->key.blend.rt[0].rgb_func == PIPE_BLEND_ADD &&
|
||||
variant->key.blend.rt[0].rgb_src_factor == PIPE_BLENDFACTOR_ONE &&
|
||||
variant->key.blend.rt[0].rgb_dst_factor == PIPE_BLENDFACTOR_INV_SRC_ALPHA &&
|
||||
variant->key.blend.rt[0].alpha_func == PIPE_BLEND_ADD &&
|
||||
variant->key.blend.rt[0].alpha_src_factor == PIPE_BLENDFACTOR_ONE &&
|
||||
variant->key.blend.rt[0].alpha_dst_factor == PIPE_BLENDFACTOR_INV_SRC_ALPHA &&
|
||||
variant->key.blend.rt[0].colormask == 0xf;
|
||||
}
|
||||
|
||||
|
||||
/* Examine the fragment shader varient and determine whether we can
|
||||
* substitute a fastpath linear shader implementation.
|
||||
*/
|
||||
void
|
||||
llvmpipe_fs_variant_linear_fastpath(struct lp_fragment_shader_variant *variant)
|
||||
{
|
||||
enum pipe_format tex_format = variant->key.samplers[0].texture_state.format;
|
||||
|
||||
if (LP_PERF & PERF_NO_SHADE) {
|
||||
variant->jit_linear = linear_red;
|
||||
return;
|
||||
}
|
||||
|
||||
if (variant->shader->kind == LP_FS_KIND_BLIT_RGBA &&
|
||||
tex_format == PIPE_FORMAT_B8G8R8A8_UNORM &&
|
||||
is_nearest_clamp_sampler(&variant->key.samplers[0])) {
|
||||
if (variant->opaque) {
|
||||
variant->jit_linear_blit = blit_rgba_blit;
|
||||
variant->jit_linear = blit_rgba;
|
||||
}
|
||||
else if (is_one_inv_src_alpha_blend(variant) &&
|
||||
util_get_cpu_caps()->has_sse2) {
|
||||
variant->jit_linear = blit_rgba_blend_premul;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (variant->shader->kind == LP_FS_KIND_BLIT_RGB1 &&
|
||||
variant->opaque &&
|
||||
(tex_format == PIPE_FORMAT_B8G8R8A8_UNORM ||
|
||||
tex_format == PIPE_FORMAT_B8G8R8X8_UNORM) &&
|
||||
is_nearest_clamp_sampler(&variant->key.samplers[0])) {
|
||||
variant->jit_linear_blit = blit_rgb1_blit;
|
||||
variant->jit_linear = blit_rgb1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (0) {
|
||||
variant->jit_linear = linear_no_op;
|
||||
return;
|
||||
}
|
||||
}
|
||||
#else
|
||||
void
|
||||
llvmpipe_fs_variant_linear_fastpath(struct lp_fragment_shader_variant *variant)
|
||||
{
|
||||
/* don't bother if there is no SSE */
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,522 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright 2010-2021 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/simple_list.h"
|
||||
|
||||
#include "pipe/p_defines.h"
|
||||
#include "util/u_inlines.h"
|
||||
#include "util/u_memory.h"
|
||||
#include "util/u_pointer.h"
|
||||
#include "util/format/u_format.h"
|
||||
#include "util/u_dump.h"
|
||||
#include "util/u_string.h"
|
||||
#include "util/os_time.h"
|
||||
#include "pipe/p_shader_tokens.h"
|
||||
#include "draw/draw_context.h"
|
||||
#include "tgsi/tgsi_dump.h"
|
||||
#include "tgsi/tgsi_scan.h"
|
||||
#include "tgsi/tgsi_parse.h"
|
||||
#include "gallivm/lp_bld_type.h"
|
||||
#include "gallivm/lp_bld_const.h"
|
||||
#include "gallivm/lp_bld_conv.h"
|
||||
#include "gallivm/lp_bld_init.h"
|
||||
#include "gallivm/lp_bld_intr.h"
|
||||
#include "gallivm/lp_bld_logic.h"
|
||||
#include "gallivm/lp_bld_tgsi.h"
|
||||
#include "gallivm/lp_bld_swizzle.h"
|
||||
#include "gallivm/lp_bld_flow.h"
|
||||
#include "gallivm/lp_bld_printf.h"
|
||||
#include "gallivm/lp_bld_debug.h"
|
||||
|
||||
#include "lp_bld_alpha.h"
|
||||
#include "lp_bld_blend.h"
|
||||
#include "lp_bld_depth.h"
|
||||
#include "lp_bld_interp.h"
|
||||
#include "lp_context.h"
|
||||
#include "lp_debug.h"
|
||||
#include "lp_perf.h"
|
||||
#include "lp_screen.h"
|
||||
#include "lp_setup.h"
|
||||
#include "lp_state.h"
|
||||
#include "lp_tex_sample.h"
|
||||
#include "lp_flush.h"
|
||||
#include "lp_state_fs.h"
|
||||
|
||||
|
||||
/**
|
||||
* Sampler.
|
||||
*/
|
||||
struct linear_sampler
|
||||
{
|
||||
struct lp_build_sampler_aos base;
|
||||
|
||||
LLVMValueRef texels_ptrs[LP_MAX_LINEAR_TEXTURES];
|
||||
|
||||
LLVMValueRef counter;
|
||||
|
||||
unsigned instance;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Provide texels to the TGSI translation.
|
||||
*
|
||||
* We don't actually do any texture sampling here, but simply hand the
|
||||
* precomputed row of texels.
|
||||
*/
|
||||
static LLVMValueRef
|
||||
emit_fetch_texel_linear(const struct lp_build_sampler_aos *base,
|
||||
struct lp_build_context *bld,
|
||||
unsigned target, /* TGSI_TEXTURE_* */
|
||||
unsigned unit,
|
||||
LLVMValueRef coords,
|
||||
const struct lp_derivatives derivs,
|
||||
enum lp_build_tex_modifier modifier)
|
||||
{
|
||||
struct linear_sampler *sampler = (struct linear_sampler *)base;
|
||||
LLVMValueRef texels_ptr;
|
||||
LLVMValueRef texel;
|
||||
|
||||
if (sampler->instance >= LP_MAX_LINEAR_TEXTURES) {
|
||||
assert(FALSE);
|
||||
return bld->undef;
|
||||
}
|
||||
|
||||
/* Pointer to a row of texels */
|
||||
texels_ptr = sampler->texels_ptrs[sampler->instance];
|
||||
|
||||
texel = lp_build_pointer_get(bld->gallivm->builder, texels_ptr,
|
||||
sampler->counter);
|
||||
assert(LLVMTypeOf(texel) == bld->vec_type);
|
||||
|
||||
/*
|
||||
* We have a struct lp_linear_sampler instance per TEX instruction,
|
||||
* _not_ per unit, as each TEX intruction will need separate storage for the
|
||||
* texels.
|
||||
*/
|
||||
(void)unit;
|
||||
++sampler->instance;
|
||||
|
||||
return texel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the main body of the fragment shader
|
||||
* Supports generating code for 4 pixel blocks and individual pixels
|
||||
*/
|
||||
static LLVMValueRef
|
||||
llvm_fragment_body(struct lp_build_context *bld,
|
||||
struct lp_fragment_shader *shader,
|
||||
struct lp_fragment_shader_variant *variant,
|
||||
struct linear_sampler* sampler,
|
||||
LLVMValueRef *inputs_ptrs,
|
||||
LLVMValueRef consts_ptr,
|
||||
LLVMValueRef blend_color,
|
||||
LLVMValueRef alpha_ref,
|
||||
struct lp_type fs_type,
|
||||
LLVMValueRef dst)
|
||||
{
|
||||
const unsigned char bgra_swizzles[4] = {2, 1, 0, 3};
|
||||
|
||||
LLVMValueRef inputs[PIPE_MAX_SHADER_INPUTS];
|
||||
LLVMValueRef outputs[PIPE_MAX_SHADER_OUTPUTS];
|
||||
|
||||
LLVMBuilderRef builder = bld->gallivm->builder;
|
||||
struct gallivm_state *gallivm = bld->gallivm;
|
||||
|
||||
LLVMValueRef src1 = lp_build_zero(gallivm, fs_type);
|
||||
|
||||
LLVMValueRef result = NULL;
|
||||
unsigned i;
|
||||
|
||||
sampler->instance = 0;
|
||||
|
||||
|
||||
/*
|
||||
* Advance inputs
|
||||
*/
|
||||
|
||||
for (i = 0; i < shader->info.base.num_inputs; ++i) {
|
||||
LLVMValueRef inputs_ptr;
|
||||
LLVMValueRef input;
|
||||
|
||||
inputs_ptr = inputs_ptrs[i];
|
||||
|
||||
input = lp_build_pointer_get(builder, inputs_ptr, sampler->counter);
|
||||
assert(LLVMTypeOf(input) == bld->vec_type);
|
||||
|
||||
inputs[i] = input;
|
||||
}
|
||||
|
||||
for ( ; i < PIPE_MAX_SHADER_INPUTS; ++i) {
|
||||
inputs[i] = bld->undef;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Translate the TGSI
|
||||
*/
|
||||
|
||||
for (i = 0; i < PIPE_MAX_SHADER_OUTPUTS; ++i) {
|
||||
outputs[i] = bld->undef;
|
||||
}
|
||||
|
||||
lp_build_tgsi_aos(gallivm, shader->base.tokens, fs_type,
|
||||
bgra_swizzles,
|
||||
consts_ptr, inputs, outputs,
|
||||
&sampler->base,
|
||||
&shader->info.base);
|
||||
|
||||
/*
|
||||
* Blend output color
|
||||
*/
|
||||
|
||||
for (i = 0; i < shader->info.base.num_outputs; ++i) {
|
||||
LLVMValueRef mask = NULL;
|
||||
LLVMValueRef output;
|
||||
unsigned cbuf;
|
||||
|
||||
if (!outputs[i])
|
||||
continue;
|
||||
|
||||
output = LLVMBuildLoad(builder, outputs[i], "");
|
||||
lp_build_name(output, "output%u", i);
|
||||
|
||||
cbuf = shader->info.base.output_semantic_index[i];
|
||||
lp_build_name(output, "cbuf%u", cbuf);
|
||||
|
||||
if (shader->info.base.output_semantic_name[i] != TGSI_SEMANTIC_COLOR || cbuf != 0)
|
||||
continue;
|
||||
|
||||
/* Perform alpha test if necessary */
|
||||
if (variant->key.alpha.enabled) {
|
||||
LLVMTypeRef vec_type = lp_build_vec_type(gallivm, fs_type);
|
||||
LLVMValueRef broadcast_alpha = lp_build_broadcast(gallivm, vec_type, alpha_ref);
|
||||
|
||||
mask = lp_build_cmp(bld, variant->key.alpha.func, output, broadcast_alpha);
|
||||
/* XXX is 4 correct? */
|
||||
mask = lp_build_swizzle_scalar_aos(bld, mask, bgra_swizzles[3], 4);
|
||||
|
||||
lp_build_name(mask, "alpha_test_mask");
|
||||
}
|
||||
|
||||
result = lp_build_blend_aos(gallivm,
|
||||
&variant->key.blend,
|
||||
variant->key.cbuf_format[i],
|
||||
fs_type,
|
||||
cbuf, /* rt */
|
||||
output, /* src */
|
||||
NULL, /* src_alpha */
|
||||
src1, /* src1 */
|
||||
NULL, /* src1_alpha */
|
||||
dst,
|
||||
mask,
|
||||
blend_color, /* const_ */
|
||||
NULL, /* const_alpha */
|
||||
bgra_swizzles,
|
||||
4);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a function that executes the fragment shader in a linear fashion.
|
||||
*/
|
||||
void
|
||||
llvmpipe_fs_variant_linear_llvm(struct llvmpipe_context *lp,
|
||||
struct lp_fragment_shader *shader,
|
||||
struct lp_fragment_shader_variant *variant)
|
||||
{
|
||||
struct gallivm_state *gallivm = variant->gallivm;
|
||||
char func_name[256];
|
||||
struct lp_type fs_type;
|
||||
LLVMTypeRef ret_type;
|
||||
LLVMTypeRef arg_types[4];
|
||||
LLVMTypeRef func_type;
|
||||
LLVMValueRef context_ptr;
|
||||
LLVMValueRef x;
|
||||
LLVMValueRef y;
|
||||
LLVMValueRef width;
|
||||
LLVMValueRef excess;
|
||||
LLVMValueRef function;
|
||||
LLVMBasicBlockRef block;
|
||||
LLVMBuilderRef builder;
|
||||
struct lp_build_context bld;
|
||||
struct linear_sampler sampler;
|
||||
struct lp_build_if_state ifstate;
|
||||
struct lp_build_for_loop_state loop;
|
||||
|
||||
LLVMValueRef consts_ptr;
|
||||
LLVMValueRef interpolators_ptr;
|
||||
LLVMValueRef samplers_ptr;
|
||||
LLVMValueRef color0_ptr;
|
||||
LLVMValueRef blend_color;
|
||||
LLVMValueRef alpha_ref;
|
||||
|
||||
LLVMValueRef inputs_ptrs[LP_MAX_LINEAR_INPUTS];
|
||||
|
||||
LLVMTypeRef int8t = LLVMInt8TypeInContext(gallivm->context);
|
||||
LLVMTypeRef int32t = LLVMInt32TypeInContext(gallivm->context);
|
||||
LLVMTypeRef pint8t = LLVMPointerType(int8t, 0);
|
||||
LLVMTypeRef pixelt = LLVMVectorType(int32t, 4);
|
||||
|
||||
unsigned attrib;
|
||||
unsigned i;
|
||||
|
||||
memset(&fs_type, 0, sizeof fs_type);
|
||||
fs_type.floating = FALSE;
|
||||
fs_type.sign = FALSE;
|
||||
fs_type.norm = TRUE;
|
||||
fs_type.width = 8;
|
||||
fs_type.length = 16;
|
||||
|
||||
if (LP_DEBUG & DEBUG_TGSI) {
|
||||
tgsi_dump(shader->base.tokens, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate the function prototype. Any change here must be reflected in
|
||||
* lp_jit.h's lp_jit_frag_func function pointer type, and vice-versa.
|
||||
*/
|
||||
|
||||
snprintf(func_name, sizeof(func_name), "fs%u_variant%u_linear",
|
||||
shader->no, variant->no);
|
||||
|
||||
ret_type = pint8t;
|
||||
arg_types[0] = variant->jit_linear_context_ptr_type; /* context */
|
||||
arg_types[1] = int32t; /* x */
|
||||
arg_types[2] = int32t; /* y */
|
||||
arg_types[3] = int32t; /* width */
|
||||
|
||||
func_type = LLVMFunctionType(ret_type, arg_types, ARRAY_SIZE(arg_types), 0);
|
||||
|
||||
function = LLVMAddFunction(gallivm->module, func_name, func_type);
|
||||
LLVMSetFunctionCallConv(function, LLVMCCallConv);
|
||||
|
||||
variant->linear_function = function;
|
||||
|
||||
/* XXX: need to propagate noalias down into color param now we are
|
||||
* passing a pointer-to-pointer?
|
||||
*/
|
||||
for (i = 0; i < ARRAY_SIZE(arg_types); ++i) {
|
||||
if (LLVMGetTypeKind(arg_types[i]) == LLVMPointerTypeKind) {
|
||||
lp_add_function_attr(function, i + 1, LP_FUNC_ATTR_NOALIAS);
|
||||
}
|
||||
}
|
||||
|
||||
context_ptr = LLVMGetParam(function, 0);
|
||||
x = LLVMGetParam(function, 1);
|
||||
y = LLVMGetParam(function, 2);
|
||||
width = LLVMGetParam(function, 3);
|
||||
|
||||
lp_build_name(context_ptr, "context");
|
||||
lp_build_name(x, "x");
|
||||
lp_build_name(y, "y");
|
||||
lp_build_name(width, "width");
|
||||
|
||||
/*
|
||||
* Function body
|
||||
*/
|
||||
|
||||
block = LLVMAppendBasicBlockInContext(gallivm->context, function, "entry");
|
||||
builder = gallivm->builder;
|
||||
|
||||
LLVMPositionBuilderAtEnd(builder, block);
|
||||
|
||||
lp_build_context_init(&bld, gallivm, fs_type);
|
||||
|
||||
/*
|
||||
* Get context data
|
||||
*/
|
||||
|
||||
consts_ptr = lp_jit_linear_context_constants(gallivm, context_ptr);
|
||||
interpolators_ptr = lp_jit_linear_context_inputs(gallivm, context_ptr);
|
||||
samplers_ptr = lp_jit_linear_context_tex(gallivm, context_ptr);
|
||||
|
||||
color0_ptr = lp_jit_linear_context_color0(gallivm, context_ptr);
|
||||
color0_ptr = LLVMBuildLoad(builder, color0_ptr, "");
|
||||
color0_ptr = LLVMBuildBitCast(builder, color0_ptr, LLVMPointerType(bld.vec_type, 0), "");
|
||||
|
||||
blend_color = lp_jit_linear_context_blend_color(gallivm, context_ptr);
|
||||
blend_color = LLVMBuildLoad(builder, blend_color, "");
|
||||
blend_color = lp_build_broadcast(gallivm, LLVMVectorType(int32t, 4), blend_color);
|
||||
blend_color = LLVMBuildBitCast(builder, blend_color, LLVMVectorType(int8t, 16), "");
|
||||
|
||||
alpha_ref = lp_jit_linear_context_alpha_ref(gallivm, context_ptr);
|
||||
alpha_ref = LLVMBuildLoad(builder, alpha_ref, "");
|
||||
|
||||
/*
|
||||
* Invoke the input interpolators
|
||||
*/
|
||||
|
||||
for (attrib = 0; attrib < shader->info.base.num_inputs; ++attrib) {
|
||||
LLVMValueRef index;
|
||||
LLVMValueRef elem;
|
||||
LLVMValueRef fetch_ptr;
|
||||
LLVMValueRef inputs_ptr;
|
||||
|
||||
assert(attrib < LP_MAX_LINEAR_INPUTS);
|
||||
if (attrib >= LP_MAX_LINEAR_INPUTS) {
|
||||
break;
|
||||
}
|
||||
|
||||
index = LLVMConstInt(int32t, attrib, 0);
|
||||
|
||||
elem = lp_build_array_get(bld.gallivm, interpolators_ptr, index);
|
||||
assert(LLVMGetTypeKind(LLVMTypeOf(elem)) == LLVMPointerTypeKind);
|
||||
|
||||
fetch_ptr = lp_build_pointer_get(builder, elem,
|
||||
LLVMConstInt(int32t, 0, 0));
|
||||
assert(LLVMGetTypeKind(LLVMTypeOf(fetch_ptr)) == LLVMPointerTypeKind);
|
||||
|
||||
/* Pointer to a row of interpolated inputs */
|
||||
elem = LLVMBuildBitCast(builder, elem, pint8t, "");
|
||||
inputs_ptr = LLVMBuildCall(builder, fetch_ptr, &elem, 1, "");
|
||||
assert(LLVMGetTypeKind(LLVMTypeOf(inputs_ptr)) == LLVMPointerTypeKind);
|
||||
|
||||
/* Mark the function read-only so that LLVM can optimize it away */
|
||||
lp_add_function_attr(inputs_ptr, -1, LP_FUNC_ATTR_READONLY);
|
||||
lp_add_function_attr(inputs_ptr, -1, LP_FUNC_ATTR_NOUNWIND);
|
||||
|
||||
lp_build_name(inputs_ptr, "input%u_ptr", attrib);
|
||||
|
||||
inputs_ptrs[attrib] = inputs_ptr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Invoke and hook up the texture samplers.
|
||||
*/
|
||||
|
||||
memset(&sampler, 0, sizeof sampler);
|
||||
sampler.base.emit_fetch_texel = &emit_fetch_texel_linear;
|
||||
|
||||
for (attrib = 0; attrib < shader->info.num_texs; ++attrib) {
|
||||
LLVMValueRef index;
|
||||
LLVMValueRef elem;
|
||||
LLVMValueRef fetch_ptr;
|
||||
LLVMValueRef texels_ptr;
|
||||
|
||||
assert(attrib < LP_MAX_LINEAR_TEXTURES);
|
||||
if (attrib >= LP_MAX_LINEAR_TEXTURES) {
|
||||
break;
|
||||
}
|
||||
|
||||
index = LLVMConstInt(int32t, attrib, 0);
|
||||
|
||||
elem = lp_build_array_get(bld.gallivm, samplers_ptr, index);
|
||||
assert(LLVMGetTypeKind(LLVMTypeOf(elem)) == LLVMPointerTypeKind);
|
||||
|
||||
fetch_ptr = lp_build_pointer_get(builder, elem, LLVMConstInt(int32t, 0, 0));
|
||||
assert(LLVMGetTypeKind(LLVMTypeOf(fetch_ptr)) == LLVMPointerTypeKind);
|
||||
|
||||
/* Pointer to a row of texels */
|
||||
elem = LLVMBuildBitCast(builder, elem, pint8t, "");
|
||||
texels_ptr = LLVMBuildCall(builder, fetch_ptr, &elem, 1, "");
|
||||
assert(LLVMGetTypeKind(LLVMTypeOf(texels_ptr)) == LLVMPointerTypeKind);
|
||||
|
||||
/* Mark the function read-only so that LLVM can optimize it away */
|
||||
lp_add_function_attr(texels_ptr, -1, LP_FUNC_ATTR_READONLY);
|
||||
lp_add_function_attr(texels_ptr, -1, LP_FUNC_ATTR_NOUNWIND);
|
||||
|
||||
lp_build_name(texels_ptr, "tex%u_ptr", attrib);
|
||||
|
||||
sampler.texels_ptrs[attrib] = texels_ptr;
|
||||
}
|
||||
|
||||
excess = LLVMBuildAnd(builder, width, LLVMConstInt(int32t, 3, 0), "");
|
||||
width = LLVMBuildLShr(builder, width, LLVMConstInt(int32t, 2, 0), "");
|
||||
|
||||
/* Loop over blocks of 4 pixels */
|
||||
lp_build_for_loop_begin(&loop, gallivm, LLVMConstInt(int32t, 0, 0), LLVMIntULT, width, LLVMConstInt(int32t, 1, 0));
|
||||
{
|
||||
LLVMValueRef value;
|
||||
sampler.counter = loop.counter;
|
||||
|
||||
/* Read 4 pixels */
|
||||
value = lp_build_pointer_get_unaligned(builder, color0_ptr, loop.counter, 4);
|
||||
|
||||
/* Perform fragment shader body */
|
||||
value = llvm_fragment_body(&bld, shader, variant, &sampler, inputs_ptrs, consts_ptr, blend_color, alpha_ref, fs_type, value);
|
||||
|
||||
/* Write 4 pixels */
|
||||
lp_build_pointer_set_unaligned(builder, color0_ptr, loop.counter, value, 4);
|
||||
}
|
||||
lp_build_for_loop_end(&loop);
|
||||
|
||||
/* Compute the edge pixels (width % 4) */
|
||||
lp_build_if(&ifstate, gallivm, LLVMBuildICmp(builder, LLVMIntNE, excess, LLVMConstInt(int32t, 0, 0), ""));
|
||||
{
|
||||
struct lp_build_loop_state loop_read, loop_write;
|
||||
LLVMValueRef buf, elem, result, pixel_ptr;
|
||||
LLVMValueRef buf_ptr = lp_build_alloca(gallivm, pixelt, "");
|
||||
|
||||
sampler.counter = width;
|
||||
|
||||
/* Get the i32* pixel pointer from the <i16x8>* element pointer */
|
||||
pixel_ptr = LLVMBuildGEP(gallivm->builder, color0_ptr, &width, 1, "");
|
||||
pixel_ptr = LLVMBuildBitCast(gallivm->builder, pixel_ptr, LLVMPointerType(int32t, 0), "");
|
||||
|
||||
/* Copy individual pixels from memory to local buffer */
|
||||
lp_build_loop_begin(&loop_read, gallivm, LLVMConstInt(int32t, 0, 0));
|
||||
{
|
||||
elem = lp_build_pointer_get(gallivm->builder, pixel_ptr, loop_read.counter);
|
||||
|
||||
buf = LLVMBuildLoad(gallivm->builder, buf_ptr, "");
|
||||
buf = LLVMBuildInsertElement(builder, buf, elem, loop_read.counter, "");
|
||||
LLVMBuildStore(builder, buf, buf_ptr);
|
||||
}
|
||||
lp_build_loop_end_cond(&loop_read, excess, LLVMConstInt(int32t, 1, 0), LLVMIntUGE);
|
||||
|
||||
/* Perform fragment shader body */
|
||||
buf = LLVMBuildLoad(gallivm->builder, buf_ptr, "");
|
||||
buf = LLVMBuildBitCast(builder, buf, bld.vec_type, "");
|
||||
|
||||
result = llvm_fragment_body(&bld, shader, variant, &sampler, inputs_ptrs, consts_ptr, blend_color, alpha_ref, fs_type, buf);
|
||||
result = LLVMBuildBitCast(builder, result, pixelt, "");
|
||||
|
||||
/* Write individual pixels from local buffer to the memory */
|
||||
lp_build_loop_begin(&loop_write, gallivm, LLVMConstInt(int32t, 0, 0));
|
||||
{
|
||||
elem = LLVMBuildExtractElement(builder, result, loop_write.counter, "");
|
||||
|
||||
lp_build_pointer_set(gallivm->builder, pixel_ptr, loop_write.counter, elem);
|
||||
}
|
||||
lp_build_loop_end_cond(&loop_write, excess, LLVMConstInt(int32t, 1, 0), LLVMIntUGE);
|
||||
}
|
||||
lp_build_endif(&ifstate);
|
||||
|
||||
|
||||
color0_ptr = LLVMBuildBitCast(builder, color0_ptr, pint8t, "");
|
||||
|
||||
LLVMBuildRet(builder, color0_ptr);
|
||||
|
||||
gallivm_verify_function(gallivm, function);
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
#include "lp_setup.h"
|
||||
#include "draw/draw_context.h"
|
||||
|
||||
struct lp_rast_state {
|
||||
struct lp_rasterizer_state {
|
||||
struct pipe_rasterizer_state lp_state;
|
||||
struct pipe_rasterizer_state draw_state;
|
||||
};
|
||||
@@ -63,7 +63,7 @@ llvmpipe_create_rasterizer_state(struct pipe_context *pipe,
|
||||
/* Partition rasterizer state into what we want the draw module to
|
||||
* handle, and what we'll look after ourselves.
|
||||
*/
|
||||
struct lp_rast_state *state = MALLOC_STRUCT(lp_rast_state);
|
||||
struct lp_rasterizer_state *state = MALLOC_STRUCT(lp_rasterizer_state);
|
||||
if (!state)
|
||||
return NULL;
|
||||
|
||||
@@ -102,8 +102,8 @@ static void
|
||||
llvmpipe_bind_rasterizer_state(struct pipe_context *pipe, void *handle)
|
||||
{
|
||||
struct llvmpipe_context *llvmpipe = llvmpipe_context(pipe);
|
||||
const struct lp_rast_state *state =
|
||||
(const struct lp_rast_state *) handle;
|
||||
const struct lp_rasterizer_state *state =
|
||||
(const struct lp_rasterizer_state *) handle;
|
||||
|
||||
if (state) {
|
||||
llvmpipe->rasterizer = &state->lp_state;
|
||||
@@ -125,6 +125,7 @@ llvmpipe_bind_rasterizer_state(struct pipe_context *pipe, void *handle)
|
||||
state->lp_state.line_rectangular);
|
||||
lp_setup_set_point_state( llvmpipe->setup,
|
||||
state->lp_state.point_size,
|
||||
state->lp_state.point_tri_clip,
|
||||
state->lp_state.point_size_per_vertex,
|
||||
state->lp_state.sprite_coord_enable,
|
||||
state->lp_state.sprite_coord_mode,
|
||||
|
||||
@@ -178,8 +178,12 @@ llvmpipe_set_sampler_views(struct pipe_context *pipe,
|
||||
}
|
||||
else if (shader == PIPE_SHADER_COMPUTE) {
|
||||
llvmpipe->cs_dirty |= LP_CSNEW_SAMPLER_VIEW;
|
||||
} else {
|
||||
}
|
||||
else if (shader == PIPE_SHADER_FRAGMENT) {
|
||||
llvmpipe->dirty |= LP_NEW_SAMPLER_VIEW;
|
||||
lp_setup_set_fragment_sampler_views(llvmpipe->setup,
|
||||
llvmpipe->num_sampler_views[PIPE_SHADER_FRAGMENT],
|
||||
llvmpipe->sampler_views[PIPE_SHADER_FRAGMENT]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -71,6 +71,7 @@ struct lp_setup_args
|
||||
LLVMValueRef a0;
|
||||
LLVMValueRef dadx;
|
||||
LLVMValueRef dady;
|
||||
LLVMValueRef key;
|
||||
|
||||
/* Derived:
|
||||
*/
|
||||
@@ -708,7 +709,7 @@ generate_setup_variant(struct lp_setup_variant_key *key,
|
||||
char func_name[64];
|
||||
LLVMTypeRef vec4f_type;
|
||||
LLVMTypeRef func_type;
|
||||
LLVMTypeRef arg_types[7];
|
||||
LLVMTypeRef arg_types[8];
|
||||
LLVMBasicBlockRef block;
|
||||
LLVMBuilderRef builder;
|
||||
int64_t t0 = 0, t1;
|
||||
@@ -752,6 +753,7 @@ generate_setup_variant(struct lp_setup_variant_key *key,
|
||||
arg_types[4] = LLVMPointerType(vec4f_type, 0); /* a0, aligned */
|
||||
arg_types[5] = LLVMPointerType(vec4f_type, 0); /* dadx, aligned */
|
||||
arg_types[6] = LLVMPointerType(vec4f_type, 0); /* dady, aligned */
|
||||
arg_types[7] = LLVMPointerType(vec4f_type, 0); /* key (placeholder) */
|
||||
|
||||
func_type = LLVMFunctionType(LLVMVoidTypeInContext(gallivm->context),
|
||||
arg_types, ARRAY_SIZE(arg_types), 0);
|
||||
@@ -769,6 +771,7 @@ generate_setup_variant(struct lp_setup_variant_key *key,
|
||||
args.a0 = LLVMGetParam(variant->function, 4);
|
||||
args.dadx = LLVMGetParam(variant->function, 5);
|
||||
args.dady = LLVMGetParam(variant->function, 6);
|
||||
args.key = LLVMGetParam(variant->function, 7);
|
||||
|
||||
lp_build_name(args.v0, "in_v0");
|
||||
lp_build_name(args.v1, "in_v1");
|
||||
@@ -777,6 +780,7 @@ generate_setup_variant(struct lp_setup_variant_key *key,
|
||||
lp_build_name(args.a0, "out_a0");
|
||||
lp_build_name(args.dadx, "out_dadx");
|
||||
lp_build_name(args.dady, "out_dady");
|
||||
lp_build_name(args.key, "key");
|
||||
|
||||
/*
|
||||
* Function body
|
||||
@@ -864,6 +868,7 @@ lp_make_setup_variant_key(struct llvmpipe_context *lp,
|
||||
|
||||
key->pgon_offset_scale = lp->rasterizer->offset_scale;
|
||||
key->pgon_offset_clamp = lp->rasterizer->offset_clamp;
|
||||
key->uses_constant_interp = 0;
|
||||
key->pad = 0;
|
||||
memcpy(key->inputs, fs->inputs, key->num_inputs * sizeof key->inputs[0]);
|
||||
for (i = 0; i < key->num_inputs; i++) {
|
||||
@@ -873,8 +878,10 @@ lp_make_setup_variant_key(struct llvmpipe_context *lp,
|
||||
else
|
||||
key->inputs[i].interp = LP_INTERP_PERSPECTIVE;
|
||||
}
|
||||
if (key->inputs[i].interp == LP_INTERP_CONSTANT) {
|
||||
key->uses_constant_interp = 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ struct lp_setup_variant_key {
|
||||
unsigned pixel_center_half:1;
|
||||
unsigned twoside:1;
|
||||
unsigned floating_point_depth:1;
|
||||
unsigned uses_constant_interp:1;
|
||||
unsigned multisample:1;
|
||||
unsigned pad:3;
|
||||
|
||||
@@ -42,7 +43,8 @@ typedef void (*lp_jit_setup_triangle)( const float (*v0)[4],
|
||||
boolean front_facing,
|
||||
float (*a0)[4],
|
||||
float (*dadx)[4],
|
||||
float (*dady)[4] );
|
||||
float (*dady)[4],
|
||||
const struct lp_setup_variant_key *key );
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -109,8 +109,6 @@ struct llvmpipe_resource
|
||||
struct llvmpipe_transfer
|
||||
{
|
||||
struct pipe_transfer base;
|
||||
|
||||
unsigned long offset;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -44,6 +44,10 @@ files_llvmpipe = files(
|
||||
'lp_jit.c',
|
||||
'lp_jit.h',
|
||||
'lp_limits.h',
|
||||
'lp_linear.c',
|
||||
'lp_linear_fastpath.c',
|
||||
'lp_linear_interp.c',
|
||||
'lp_linear_sampler.c',
|
||||
'lp_memory.c',
|
||||
'lp_memory.h',
|
||||
'lp_perf.c',
|
||||
@@ -54,7 +58,10 @@ files_llvmpipe = files(
|
||||
'lp_rast.c',
|
||||
'lp_rast_debug.c',
|
||||
'lp_rast.h',
|
||||
'lp_rast_linear.c',
|
||||
'lp_rast_linear_fallback.c',
|
||||
'lp_rast_priv.h',
|
||||
'lp_rast_rect.c',
|
||||
'lp_rast_tri.c',
|
||||
'lp_rast_tri_tmp.h',
|
||||
'lp_scene.c',
|
||||
@@ -64,10 +71,12 @@ files_llvmpipe = files(
|
||||
'lp_screen.c',
|
||||
'lp_screen.h',
|
||||
'lp_setup.c',
|
||||
'lp_setup_analysis.c',
|
||||
'lp_setup_context.h',
|
||||
'lp_setup.h',
|
||||
'lp_setup_line.c',
|
||||
'lp_setup_point.c',
|
||||
'lp_setup_rect.c',
|
||||
'lp_setup_tri.c',
|
||||
'lp_setup_vbuf.c',
|
||||
'lp_state_blend.c',
|
||||
@@ -77,6 +86,10 @@ files_llvmpipe = files(
|
||||
'lp_state_cs.h',
|
||||
'lp_state_fs.c',
|
||||
'lp_state_fs.h',
|
||||
'lp_state_fs_analysis.c',
|
||||
'lp_state_fs_fastpath.c',
|
||||
'lp_state_fs_linear.c',
|
||||
'lp_state_fs_linear_llvm.c',
|
||||
'lp_state_gs.c',
|
||||
'lp_state.h',
|
||||
'lp_state_rasterizer.c',
|
||||
|
||||
Reference in New Issue
Block a user