i965: Add user clip planes support to gen6.

Fixes piglit user-clip, and compiz desktop switching when dragging a
window and using just 2 desktops.  Bug #30446.
This commit is contained in:
Eric Anholt 2010-10-27 11:00:14 -07:00
parent 85a08f8fc7
commit e30a3e7aa0
5 changed files with 125 additions and 33 deletions

View File

@ -930,6 +930,11 @@
#define CMD_3D_CLIP_STATE 0x7812 /* GEN6+ */
/* DW1 */
# define GEN6_CLIP_STATISTICS_ENABLE (1 << 10)
/**
* Just does cheap culling based on the clip distance. Bits must be
* disjoint with USER_CLIP_CLIP_DISTANCE bits.
*/
# define GEN6_USER_CLIP_CULL_DISTANCES_SHIFT 0
/* DW2 */
# define GEN6_CLIP_ENABLE (1 << 31)
# define GEN6_CLIP_API_OGL (0 << 30)
@ -937,6 +942,8 @@
# define GEN6_CLIP_XY_TEST (1 << 28)
# define GEN6_CLIP_Z_TEST (1 << 27)
# define GEN6_CLIP_GB_TEST (1 << 26)
/** 8-bit field of which user clip distances to clip aganist. */
# define GEN6_USER_CLIP_CLIP_DISTANCES_SHIFT 16
# define GEN6_CLIP_MODE_NORMAL (0 << 13)
# define GEN6_CLIP_MODE_REJECT_ALL (3 << 13)
# define GEN6_CLIP_MODE_ACCEPT_ALL (4 << 13)

View File

@ -165,13 +165,20 @@ static void brw_vs_alloc_regs( struct brw_vs_compile *c )
/* User clip planes from curbe:
*/
if (c->key.nr_userclip) {
for (i = 0; i < c->key.nr_userclip; i++) {
c->userplane[i] = stride( brw_vec4_grf(reg+3+i/2, (i%2) * 4), 0, 4, 1);
}
if (intel->gen >= 6) {
for (i = 0; i < c->key.nr_userclip; i++) {
c->userplane[i] = stride(brw_vec4_grf(reg + i / 2,
(i % 2) * 4), 0, 4, 1);
}
reg += ALIGN(c->key.nr_userclip, 2) / 2;
} else {
for (i = 0; i < c->key.nr_userclip; i++) {
c->userplane[i] = stride(brw_vec4_grf(reg + (6 + i) / 2,
(i % 2) * 4), 0, 4, 1);
}
reg += (ALIGN(6 + c->key.nr_userclip, 4) / 4) * 2;
}
/* Deal with curbe alignment:
*/
reg += ((6 + c->key.nr_userclip + 3) / 4) * 2;
}
/* Vertex program parameters from curbe:
@ -253,9 +260,11 @@ static void brw_vs_alloc_regs( struct brw_vs_compile *c )
c->first_output = reg;
c->first_overflow_output = 0;
if (intel->gen >= 6)
mrf = 3; /* no more pos store in attribute */
else if (intel->gen == 5)
if (intel->gen >= 6) {
mrf = 3;
if (c->key.nr_userclip)
mrf += 2;
} else if (intel->gen == 5)
mrf = 8;
else
mrf = 4;
@ -372,9 +381,13 @@ static void brw_vs_alloc_regs( struct brw_vs_compile *c )
/* See emit_vertex_write() for where the VUE's overhead on top of the
* attributes comes from.
*/
if (intel->gen >= 6)
c->prog_data.urb_entry_size = (attributes_in_vue + 2 + 7) / 8;
else if (intel->gen == 5)
if (intel->gen >= 6) {
int header_regs = 2;
if (c->key.nr_userclip)
header_regs += 2;
c->prog_data.urb_entry_size = (attributes_in_vue + header_regs + 7) / 8;
} else if (intel->gen == 5)
c->prog_data.urb_entry_size = (attributes_in_vue + 6 + 3) / 4;
else
c->prog_data.urb_entry_size = (attributes_in_vue + 2 + 3) / 4;
@ -1392,9 +1405,33 @@ static void emit_vertex_write( struct brw_vs_compile *c)
/* Update the header for point size, user clipping flags, and -ve rhw
* workaround.
*/
if ((c->prog_data.outputs_written & BITFIELD64_BIT(VERT_RESULT_PSIZ)) ||
c->key.nr_userclip || brw->has_negative_rhw_bug)
{
if (intel->gen >= 6) {
struct brw_reg m1 = brw_message_reg(1);
/* On gen6, m1 has each value in a separate dword, so we never
* need to mess with a temporary for computing the m1 value.
*/
brw_MOV(p, retype(m1, BRW_REGISTER_TYPE_UD), brw_imm_ud(0));
if (c->prog_data.outputs_written & BITFIELD64_BIT(VERT_RESULT_PSIZ)) {
brw_MOV(p, brw_writemask(m1, WRITEMASK_W),
brw_swizzle1(c->regs[PROGRAM_OUTPUT][VERT_RESULT_PSIZ], 0));
}
/* Set the user clip distances in dword 8-15. (m3-4)*/
if (c->key.nr_userclip) {
for (i = 0; i < c->key.nr_userclip; i++) {
struct brw_reg m;
if (i < 4)
m = brw_message_reg(3);
else
m = brw_message_reg(4);
brw_DP4(p, brw_writemask(m, (1 << (i & 7))),pos, c->userplane[i]);
}
}
} else if ((c->prog_data.outputs_written &
BITFIELD64_BIT(VERT_RESULT_PSIZ)) ||
c->key.nr_userclip || brw->has_negative_rhw_bug) {
struct brw_reg header1 = retype(get_tmp(c), BRW_REGISTER_TYPE_UD);
GLuint i;
@ -1404,11 +1441,10 @@ static void emit_vertex_write( struct brw_vs_compile *c)
if (c->prog_data.outputs_written & BITFIELD64_BIT(VERT_RESULT_PSIZ)) {
struct brw_reg psiz = c->regs[PROGRAM_OUTPUT][VERT_RESULT_PSIZ];
if (intel->gen < 6) {
brw_MUL(p, brw_writemask(header1, WRITEMASK_W), brw_swizzle1(psiz, 0), brw_imm_f(1<<11));
brw_AND(p, brw_writemask(header1, WRITEMASK_W), header1, brw_imm_ud(0x7ff<<8));
} else
brw_MOV(p, brw_writemask(header1, WRITEMASK_W), brw_swizzle1(psiz, 0));
brw_MUL(p, brw_writemask(header1, WRITEMASK_W),
brw_swizzle1(psiz, 0), brw_imm_f(1<<11));
brw_AND(p, brw_writemask(header1, WRITEMASK_W),
header1, brw_imm_ud(0x7ff<<8));
}
for (i = 0; i < c->key.nr_userclip; i++) {
@ -1461,12 +1497,14 @@ static void emit_vertex_write( struct brw_vs_compile *c)
* dword 0-3 (m1) of the header is indices, point width, clip flags.
* dword 4-7 (m2) is the 4D space position
* dword 8-15 (m3,m4) of the vertex header is the user clip distance if
* enabled. We don't use it, so skip it.
* m3 is the first vertex element data we fill, which is the vertex
* position.
* enabled.
* m3 or 5 is the first vertex element data we fill, which is
* the vertex position.
*/
brw_MOV(p, brw_message_reg(2), pos);
len_vertex_header = 1;
if (c->key.nr_userclip > 0)
len_vertex_header += 2;
} else if (intel->gen == 5) {
/* There are 20 DWs (D0-D19) in VUE header on Ironlake:
* dword 0-3 (m1) of the header is indices, point width, clip flags.

View File

@ -28,6 +28,7 @@
#include "brw_context.h"
#include "brw_state.h"
#include "brw_defines.h"
#include "brw_util.h"
#include "intel_batchbuffer.h"
static void
@ -36,7 +37,7 @@ upload_clip_state(struct brw_context *brw)
struct intel_context *intel = &brw->intel;
struct gl_context *ctx = &intel->ctx;
uint32_t depth_clamp = 0;
uint32_t provoking;
uint32_t provoking, userclip;
if (!ctx->Transform.DepthClamp)
depth_clamp = GEN6_CLIP_Z_TEST;
@ -50,6 +51,9 @@ upload_clip_state(struct brw_context *brw)
(1 << GEN6_CLIP_LINE_PROVOKE_SHIFT);
}
/* _NEW_TRANSFORM */
userclip = (1 << brw_count_bits(ctx->Transform.ClipPlanesEnabled)) - 1;
BEGIN_BATCH(4);
OUT_BATCH(CMD_3D_CLIP_STATE << 16 | (4 - 2));
OUT_BATCH(GEN6_CLIP_STATISTICS_ENABLE);
@ -57,6 +61,7 @@ upload_clip_state(struct brw_context *brw)
GEN6_CLIP_API_OGL |
GEN6_CLIP_MODE_NORMAL |
GEN6_CLIP_XY_TEST |
userclip << GEN6_USER_CLIP_CLIP_DISTANCES_SHIFT |
depth_clamp |
provoking);
OUT_BATCH(GEN6_CLIP_FORCE_ZERO_RTAINDEX);

View File

@ -73,12 +73,19 @@ upload_sf_state(struct brw_context *brw)
/* _NEW_BUFFER */
GLboolean render_to_fbo = brw->intel.ctx.DrawBuffer->Name != 0;
int attr = 0;
int urb_start;
/* _NEW_TRANSFORM */
if (ctx->Transform.ClipPlanesEnabled)
urb_start = 2;
else
urb_start = 1;
dw1 =
GEN6_SF_SWIZZLE_ENABLE |
num_outputs << GEN6_SF_NUM_OUTPUTS_SHIFT |
(num_inputs + 1) / 2 << GEN6_SF_URB_ENTRY_READ_LENGTH_SHIFT |
1 << GEN6_SF_URB_ENTRY_READ_OFFSET_SHIFT;
urb_start << GEN6_SF_URB_ENTRY_READ_OFFSET_SHIFT;
dw2 = GEN6_SF_VIEWPORT_TRANSFORM_ENABLE |
GEN6_SF_STATISTICS_ENABLE;
dw3 = 0;
@ -195,7 +202,8 @@ const struct brw_tracked_state gen6_sf_state = {
_NEW_POLYGON |
_NEW_LINE |
_NEW_SCISSOR |
_NEW_BUFFERS),
_NEW_BUFFERS |
_NEW_TRANSFORM),
.brw = BRW_NEW_CONTEXT,
.cache = CACHE_NEW_VS_PROG
},

View File

@ -44,7 +44,8 @@ upload_vs_state(struct brw_context *brw)
drm_intel_bo *constant_bo;
int i;
if (vp->use_const_buffer || nr_params == 0) {
if (vp->use_const_buffer || (nr_params == 0 &&
!ctx->Transform.ClipPlanesEnabled)) {
/* Disable the push constant buffers. */
BEGIN_BATCH(5);
OUT_BATCH(CMD_3D_CONSTANT_VS_STATE << 16 | (5 - 2));
@ -54,6 +55,9 @@ upload_vs_state(struct brw_context *brw)
OUT_BATCH(0);
ADVANCE_BATCH();
} else {
int params_uploaded = 0;
float *param;
if (brw->vertex_program->IsNVProgram)
_mesa_load_tracked_matrices(ctx);
@ -63,14 +67,44 @@ upload_vs_state(struct brw_context *brw)
_mesa_load_state_parameters(ctx, vp->program.Base.Parameters);
constant_bo = drm_intel_bo_alloc(intel->bufmgr, "VS constant_bo",
nr_params * 4 * sizeof(float),
(MAX_CLIP_PLANES + nr_params) *
4 * sizeof(float),
4096);
drm_intel_gem_bo_map_gtt(constant_bo);
for (i = 0; i < nr_params; i++) {
memcpy((char *)constant_bo->virtual + i * 4 * sizeof(float),
vp->program.Base.Parameters->ParameterValues[i],
4 * sizeof(float));
param = constant_bo->virtual;
/* This should be loaded like any other param, but it's ad-hoc
* until we redo the VS backend.
*/
for (i = 0; i < MAX_CLIP_PLANES; i++) {
if (ctx->Transform.ClipPlanesEnabled & (1 << i)) {
memcpy(param, ctx->Transform._ClipUserPlane[i], 4 * sizeof(float));
param += 4;
params_uploaded++;
}
}
/* Align to a reg for convenience for brw_vs_emit.c */
if (params_uploaded & 1) {
param += 4;
params_uploaded++;
}
for (i = 0; i < nr_params; i++) {
memcpy(param, vp->program.Base.Parameters->ParameterValues[i],
4 * sizeof(float));
param += 4;
params_uploaded++;
}
if (0) {
printf("VS constant buffer:\n");
for (i = 0; i < params_uploaded; i++) {
float *buf = (float *)constant_bo->virtual + i * 4;
printf("%d: %f %f %f %f\n",
i, buf[0], buf[1], buf[2], buf[3]);
}
}
drm_intel_gem_bo_unmap_gtt(constant_bo);
BEGIN_BATCH(5);
@ -79,7 +113,7 @@ upload_vs_state(struct brw_context *brw)
(5 - 2));
OUT_RELOC(constant_bo,
I915_GEM_DOMAIN_RENDER, 0, /* XXX: bad domain */
ALIGN(nr_params, 2) / 2 - 1);
ALIGN(params_uploaded, 2) / 2 - 1);
OUT_BATCH(0);
OUT_BATCH(0);
OUT_BATCH(0);