_brw_cmd_pack(cmd)(brw, (void *)_dst, &name), \
_dst = NULL)
+#if GEN_GEN >= 7
+MAYBE_UNUSED static void
+emit_lrm(struct brw_context *brw, uint32_t reg, struct brw_address addr)
+{
+ brw_batch_emit(brw, GENX(MI_LOAD_REGISTER_MEM), lrm) {
+ lrm.RegisterAddress = reg;
+ lrm.MemoryAddress = addr;
+ }
+}
+#endif
+
+MAYBE_UNUSED static void
+emit_lri(struct brw_context *brw, uint32_t reg, uint32_t imm)
+{
+ brw_batch_emit(brw, GENX(MI_LOAD_REGISTER_IMM), lri) {
+ lri.RegisterOffset = reg;
+ lri.DataDWord = imm;
+ }
+}
+
+#if GEN_IS_HASWELL || GEN_GEN >= 8
+MAYBE_UNUSED static void
+emit_lrr(struct brw_context *brw, uint32_t dst, uint32_t src)
+{
+ brw_batch_emit(brw, GENX(MI_LOAD_REGISTER_REG), lrr) {
+ lrr.SourceRegisterAddress = src;
+ lrr.DestinationRegisterAddress = dst;
+ }
+}
+#endif
+
/**
* Polygon stipple packet
*/
* to a FBO (i.e. any named frame buffer object), we *don't*
* need to invert - we already match the layout.
*/
- if (_mesa_is_winsys_fbo(ctx->DrawBuffer)) {
+ if (ctx->DrawBuffer->FlipY) {
for (unsigned i = 0; i < 32; i++)
poly.PatternRow[i] = ctx->PolygonStipple[31 - i]; /* invert */
} else {
* to a user-created FBO then our native pixel coordinate system
* works just fine, and there's no window system to worry about.
*/
- if (_mesa_is_winsys_fbo(ctx->DrawBuffer)) {
+ if (ctx->DrawBuffer->FlipY) {
poly.PolygonStippleYOffset =
(32 - (_mesa_geometric_height(ctx->DrawBuffer) & 31)) & 31;
}
#endif
#if GEN_GEN == 11
- .VertexBufferMOCS = ICL_MOCS_WB,
+ .MOCS = ICL_MOCS_WB,
#elif GEN_GEN == 10
- .VertexBufferMOCS = CNL_MOCS_WB,
+ .MOCS = CNL_MOCS_WB,
#elif GEN_GEN == 9
- .VertexBufferMOCS = SKL_MOCS_WB,
+ .MOCS = SKL_MOCS_WB,
#elif GEN_GEN == 8
- .VertexBufferMOCS = BDW_MOCS_WB,
+ .MOCS = BDW_MOCS_WB,
#elif GEN_GEN == 7
- .VertexBufferMOCS = GEN7_MOCS_L3,
+ .MOCS = GEN7_MOCS_L3,
#endif
};
* In the relocation world, we have no idea what the addresses will be, so
* we can't apply this workaround. Instead, we tell the kernel to move it
* to the low 4GB regardless.
+ *
+ * This HW issue is gone on Gen11+.
*/
static void
vf_invalidate_for_vb_48bit_transitions(struct brw_context *brw)
{
-#if GEN_GEN >= 8
+#if GEN_GEN >= 8 && GEN_GEN < 11
bool need_invalidate = false;
- unsigned i;
- for (i = 0; i < brw->vb.nr_buffers; i++) {
+ for (unsigned i = 0; i < brw->vb.nr_buffers; i++) {
uint16_t high_bits = pinned_bo_high_bits(brw->vb.buffers[i].bo);
if (high_bits != brw->vb.last_bo_high_bits[i]) {
}
}
- /* Don't bother with draw parameter buffers - those are generated by
- * the driver so we can select a consistent memory zone.
- */
+ if (brw->draw.draw_params_bo) {
+ uint16_t high_bits = pinned_bo_high_bits(brw->draw.draw_params_bo);
+
+ if (brw->vb.last_bo_high_bits[brw->vb.nr_buffers] != high_bits) {
+ need_invalidate = true;
+ brw->vb.last_bo_high_bits[brw->vb.nr_buffers] = high_bits;
+ }
+ }
+
+ if (brw->draw.derived_draw_params_bo) {
+ uint16_t high_bits = pinned_bo_high_bits(brw->draw.derived_draw_params_bo);
+
+ if (brw->vb.last_bo_high_bits[brw->vb.nr_buffers + 1] != high_bits) {
+ need_invalidate = true;
+ brw->vb.last_bo_high_bits[brw->vb.nr_buffers + 1] = high_bits;
+ }
+ }
if (need_invalidate) {
- brw_emit_pipe_control_flush(brw, PIPE_CONTROL_VF_CACHE_INVALIDATE);
+ brw_emit_pipe_control_flush(brw, PIPE_CONTROL_VF_CACHE_INVALIDATE | PIPE_CONTROL_CS_STALL);
}
#endif
}
for (unsigned i = 0; i < brw->vb.nr_enabled; i++) {
struct brw_vertex_element *input = brw->vb.enabled[i];
const struct gl_array_attributes *glattrib = input->glattrib;
- uint32_t format = brw_get_vertex_surface_type(brw, glattrib);
+ uint32_t format = brw_get_vertex_surface_type(brw, &glattrib->Format);
if (uploads_needed(format, input->is_dual_slot) > 1)
nr_elements++;
for (i = 0; i < brw->vb.nr_enabled; i++) {
const struct brw_vertex_element *input = brw->vb.enabled[i];
const struct gl_array_attributes *glattrib = input->glattrib;
- uint32_t format = brw_get_vertex_surface_type(brw, glattrib);
+ uint32_t format = brw_get_vertex_surface_type(brw, &glattrib->Format);
uint32_t comp0 = VFCOMP_STORE_SRC;
uint32_t comp1 = VFCOMP_STORE_SRC;
uint32_t comp2 = VFCOMP_STORE_SRC;
const struct gl_array_attributes *glattrib = input->glattrib;
const int size = (GEN_GEN < 8 && is_passthru_format(format)) ?
- upload_format_size(upload_format) : glattrib->Size;
+ upload_format_size(upload_format) : glattrib->Format.Size;
switch (size) {
case 0: comp0 = VFCOMP_STORE_0;
case 1: comp1 = VFCOMP_STORE_0;
case 2: comp2 = VFCOMP_STORE_0;
case 3:
- if (GEN_GEN >= 8 && glattrib->Doubles) {
+ if (GEN_GEN >= 8 && glattrib->Format.Doubles) {
comp3 = VFCOMP_STORE_0;
- } else if (glattrib->Integer) {
+ } else if (glattrib->Format.Integer) {
comp3 = VFCOMP_STORE_1_INT;
} else {
comp3 = VFCOMP_STORE_1_FP;
* to be specified as VFCOMP_STORE_0 in order to output a 256-bit
* vertex element."
*/
- if (glattrib->Doubles && !input->is_dual_slot) {
+ if (glattrib->Format.Doubles && !input->is_dual_slot) {
/* Store vertex elements which correspond to double and dvec2 vertex
* shader inputs as 128-bit vertex elements, instead of 256-bits.
*/
#if GEN_GEN >= 6
if (gen6_edgeflag_input) {
const struct gl_array_attributes *glattrib = gen6_edgeflag_input->glattrib;
- const uint32_t format = brw_get_vertex_surface_type(brw, glattrib);
+ const uint32_t format = brw_get_vertex_surface_type(brw, &glattrib->Format);
struct GENX(VERTEX_ELEMENT_STATE) elem_state = {
.Valid = true,
.mesa = _NEW_POLYGON,
.brw = BRW_NEW_BATCH |
BRW_NEW_BLORP |
+ BRW_NEW_VERTEX_PROGRAM |
BRW_NEW_VERTICES |
BRW_NEW_VS_PROG_DATA,
},
*/
ib.BufferStartingAddress = ro_32_bo(brw->ib.bo, 0);
#if GEN_GEN >= 8
- ib.IndexBufferMOCS = GEN_GEN >= 9 ? SKL_MOCS_WB : BDW_MOCS_WB;
+ ib.MOCS = GEN_GEN >= 9 ? SKL_MOCS_WB : BDW_MOCS_WB;
ib.BufferSize = brw->ib.size;
#else
ib.BufferEndingAddress = ro_bo(brw->ib.bo, brw->ib.size - 1);
clip.ScreenSpaceViewportYMax = 1;
clip.ViewportXYClipTestEnable = true;
- clip.ViewportZClipTestEnable = !ctx->Transform.DepthClamp;
+ clip.ViewportZClipTestEnable = !(ctx->Transform.DepthClampNear &&
+ ctx->Transform.DepthClampFar);
/* _NEW_TRANSFORM */
if (GEN_GEN == 5 || GEN_IS_G4X) {
#endif
#if GEN_GEN == 7
- clip.FrontWinding = brw->polygon_front_bit == _mesa_is_user_fbo(fb);
+ clip.FrontWinding = brw->polygon_front_bit != fb->FlipY;
if (ctx->Polygon.CullFlag) {
switch (ctx->Polygon.CullFaceMode) {
clip.UserClipDistanceCullTestEnableBitmask =
brw_vue_prog_data(brw->vs.base.prog_data)->cull_distance_mask;
- clip.ViewportZClipTestEnable = !ctx->Transform.DepthClamp;
+ clip.ViewportZClipTestEnable = !(ctx->Transform.DepthClampNear &&
+ ctx->Transform.DepthClampFar);
#endif
/* _NEW_LIGHT */
#if GEN_GEN <= 7
/* _NEW_BUFFERS */
- bool render_to_fbo = _mesa_is_user_fbo(ctx->DrawBuffer);
+ bool flip_y = ctx->DrawBuffer->FlipY;
UNUSED const bool multisampled_fbo =
_mesa_geometric_samples(ctx->DrawBuffer) > 1;
#endif
#if GEN_GEN <= 7
/* _NEW_POLYGON */
- sf.FrontWinding = brw->polygon_front_bit == render_to_fbo;
+ sf.FrontWinding = brw->polygon_front_bit != flip_y;
#if GEN_GEN >= 6
sf.GlobalDepthOffsetEnableSolid = ctx->Polygon.OffsetFill;
sf.GlobalDepthOffsetEnableWireframe = ctx->Polygon.OffsetLine;
* Window coordinates in an FBO are inverted, which means point
* sprite origin must be inverted, too.
*/
- if ((ctx->Point.SpriteOrigin == GL_LOWER_LEFT) != render_to_fbo) {
+ if ((ctx->Point.SpriteOrigin == GL_LOWER_LEFT) == flip_y) {
sf.PointSpriteTextureCoordinateOrigin = LOWERLEFT;
} else {
sf.PointSpriteTextureCoordinateOrigin = UPPERLEFT;
/* Pointer to the WM constant buffer. Covered by the set of
* state flags from gen6_upload_wm_push_constants.
*/
- wmcp.PointertoPSConstantBuffer0 = stage_state->push_const_offset;
- wmcp.PSConstantBuffer0ReadLength = stage_state->push_const_size - 1;
+ wmcp.ConstantBody.PointertoConstantBuffer0 = stage_state->push_const_offset;
+ wmcp.ConstantBody.ConstantBuffer0ReadLength = stage_state->push_const_size - 1;
}
}
#endif
brw_wm_prog_data_dispatch_grf_start_reg(wm_prog_data, wm, 2));
}
#elif GEN_GEN == 6
- /* On gen5, we have multiple shader kernels and we no longer specify a
+ /* On gen6, we have multiple shader kernels and we no longer specify a
* register count for each one.
*/
wm.KernelStartPointer0 = stage_state->prog_offset +
if (wm_prog_data->base.use_alt_mode)
wm.FloatingPointMode = FLOATING_POINT_MODE_Alternate;
- wm.SamplerCount = GEN_GEN == 5 ?
+ /* WA_1606682166 */
+ wm.SamplerCount = (GEN_GEN == 5 || GEN_GEN == 11) ?
0 : DIV_ROUND_UP(stage_state->sampler_count, 4);
wm.BindingTableEntryCount =
#define INIT_THREAD_DISPATCH_FIELDS(pkt, prefix) \
pkt.KernelStartPointer = KSP(brw, stage_state->prog_offset); \
+ /* WA_1606682166 */ \
pkt.SamplerCount = \
+ GEN_GEN == 11 ? \
+ 0 : \
DIV_ROUND_UP(CLAMP(stage_state->sampler_count, 0, 16), 4); \
+ /* Gen 11 workarounds table #2056 WABTPPrefetchDisable suggests to \
+ * disable prefetching of binding tables in A0 and B0 steppings. \
+ * TODO: Revisit this WA on C0 stepping. \
+ */ \
pkt.BindingTableEntryCount = \
+ GEN_GEN == 11 ? \
+ 0 : \
stage_prog_data->binding_table.size_bytes / 4; \
pkt.FloatingPointMode = stage_prog_data->use_alt_mode; \
\
brw_batch_emit(brw, GENX(3DSTATE_CONSTANT_VS), cvs) {
if (stage_state->push_const_size != 0) {
cvs.Buffer0Valid = true;
- cvs.PointertoVSConstantBuffer0 = stage_state->push_const_offset;
- cvs.VSConstantBuffer0ReadLength = stage_state->push_const_size - 1;
+ cvs.ConstantBody.PointertoConstantBuffer0 = stage_state->push_const_offset;
+ cvs.ConstantBody.ConstantBuffer0ReadLength = stage_state->push_const_size - 1;
}
}
#endif
for (unsigned i = 0; i < viewport_count; i++) {
/* _NEW_VIEWPORT | _NEW_TRANSFORM */
const struct gl_viewport_attrib *vp = &ctx->ViewportArray[i];
- if (ctx->Transform.DepthClamp) {
+ if (ctx->Transform.DepthClampNear && ctx->Transform.DepthClampFar) {
+ ccv.MinimumDepth = MIN2(vp->Near, vp->Far);
+ ccv.MaximumDepth = MAX2(vp->Near, vp->Far);
+ } else if (ctx->Transform.DepthClampNear) {
ccv.MinimumDepth = MIN2(vp->Near, vp->Far);
+ ccv.MaximumDepth = 0.0;
+ } else if (ctx->Transform.DepthClampFar) {
+ ccv.MinimumDepth = 0.0;
ccv.MaximumDepth = MAX2(vp->Near, vp->Far);
} else {
ccv.MinimumDepth = 0.0;
static void
set_scissor_bits(const struct gl_context *ctx, int i,
- bool render_to_fbo, unsigned fb_width, unsigned fb_height,
+ bool flip_y, unsigned fb_width, unsigned fb_height,
struct GENX(SCISSOR_RECT) *sc)
{
int bbox[4];
sc->ScissorRectangleXMax = 0;
sc->ScissorRectangleYMin = 1;
sc->ScissorRectangleYMax = 0;
- } else if (render_to_fbo) {
+ } else if (!flip_y) {
/* texmemory: Y=0=bottom */
sc->ScissorRectangleXMin = bbox[0];
sc->ScissorRectangleXMax = bbox[1] - 1;
genX(upload_scissor_state)(struct brw_context *brw)
{
struct gl_context *ctx = &brw->ctx;
- const bool render_to_fbo = _mesa_is_user_fbo(ctx->DrawBuffer);
+ const bool flip_y = ctx->DrawBuffer->FlipY;
struct GENX(SCISSOR_RECT) scissor;
uint32_t scissor_state_offset;
const unsigned int fb_width = _mesa_geometric_width(ctx->DrawBuffer);
* inclusive but max is exclusive.
*/
for (unsigned i = 0; i < viewport_count; i++) {
- set_scissor_bits(ctx, i, render_to_fbo, fb_width, fb_height, &scissor);
+ set_scissor_bits(ctx, i, flip_y, fb_width, fb_height, &scissor);
GENX(SCISSOR_RECT_pack)(
NULL, scissor_map + i * GENX(SCISSOR_RECT_length), &scissor);
}
*/
const float gb_size = GEN_GEN >= 7 ? 16384.0f : 8192.0f;
+ /* Workaround: prevent gpu hangs on SandyBridge
+ * by disabling guardband clipping for odd dimensions.
+ */
+ if (GEN_GEN == 6 && (fb_width & 1 || fb_height & 1)) {
+ *xmin = -1.0f;
+ *xmax = 1.0f;
+ *ymin = -1.0f;
+ *ymax = 1.0f;
+ return;
+ }
+
if (m00 != 0 && m11 != 0) {
/* First, we compute the screen-space render area */
const float ss_ra_xmin = MIN3( 0, m30 + m00, m30 - m00);
const unsigned viewport_count = brw->clip.viewport_count;
/* _NEW_BUFFERS */
- const bool render_to_fbo = _mesa_is_user_fbo(ctx->DrawBuffer);
+ const bool flip_y = ctx->DrawBuffer->FlipY;
const uint32_t fb_width = (float)_mesa_geometric_width(ctx->DrawBuffer);
const uint32_t fb_height = (float)_mesa_geometric_height(ctx->DrawBuffer);
#endif
/* _NEW_BUFFERS */
- if (render_to_fbo) {
- y_scale = 1.0;
- y_bias = 0;
- } else {
+ if (flip_y) {
y_scale = -1.0;
y_bias = (float)fb_height;
+ } else {
+ y_scale = 1.0;
+ y_bias = 0;
}
for (unsigned i = 0; i < brw->clip.viewport_count; i++) {
clv.YMaxClipGuardband = gb_ymax;
#if GEN_GEN < 6
- set_scissor_bits(ctx, i, render_to_fbo, fb_width, fb_height,
+ set_scissor_bits(ctx, i, flip_y, fb_width, fb_height,
&sfv.ScissorRectangle);
#elif GEN_GEN >= 8
/* _NEW_VIEWPORT | _NEW_BUFFERS: Screen Space Viewport
const float viewport_Ymax =
MIN2(ctx->ViewportArray[i].Y + ctx->ViewportArray[i].Height, fb_height);
- if (render_to_fbo) {
+ if (flip_y) {
sfv.XMinViewPort = viewport_Xmin;
sfv.XMaxViewPort = viewport_Xmax - 1;
- sfv.YMinViewPort = viewport_Ymin;
- sfv.YMaxViewPort = viewport_Ymax - 1;
+ sfv.YMinViewPort = fb_height - viewport_Ymax;
+ sfv.YMaxViewPort = fb_height - viewport_Ymin - 1;
} else {
sfv.XMinViewPort = viewport_Xmin;
sfv.XMaxViewPort = viewport_Xmax - 1;
- sfv.YMinViewPort = fb_height - viewport_Ymax;
- sfv.YMaxViewPort = fb_height - viewport_Ymin - 1;
+ sfv.YMinViewPort = viewport_Ymin;
+ sfv.YMaxViewPort = viewport_Ymax - 1;
}
#endif
brw_batch_emit(brw, GENX(3DSTATE_CONSTANT_GS), cgs) {
if (active && stage_state->push_const_size != 0) {
cgs.Buffer0Valid = true;
- cgs.PointertoGSConstantBuffer0 = stage_state->push_const_offset;
- cgs.GSConstantBuffer0ReadLength = stage_state->push_const_size - 1;
+ cgs.ConstantBody.PointertoConstantBuffer0 = stage_state->push_const_offset;
+ cgs.ConstantBody.ConstantBuffer0ReadLength = stage_state->push_const_size - 1;
}
}
#endif
#if GEN_GEN < 7
gs.SOStatisticsEnable = true;
if (gs_prog->info.has_transform_feedback_varyings)
- gs.SVBIPayloadEnable = true;
+ gs.SVBIPayloadEnable = _mesa_is_xfb_active_and_unpaused(ctx);
/* GEN6_GS_SPF_MODE and GEN6_GS_VECTOR_MASK_ENABLE are enabled as it
* was previously done for gen6.
dstA = fix_dual_blend_alpha_to_one(dstA);
}
- entry->ColorBufferBlendEnable = true;
+ /* BRW_NEW_FS_PROG_DATA */
+ const struct brw_wm_prog_data *wm_prog_data =
+ brw_wm_prog_data(brw->wm.base.prog_data);
+
+ /* The Dual Source Blending documentation says:
+ *
+ * "If SRC1 is included in a src/dst blend factor and
+ * a DualSource RT Write message is not used, results
+ * are UNDEFINED. (This reflects the same restriction in DX APIs,
+ * where undefined results are produced if “o1” is not written
+ * by a PS – there are no default values defined).
+ * If SRC1 is not included in a src/dst blend factor,
+ * dual source blending must be disabled."
+ *
+ * There is no way to gracefully fix this undefined situation
+ * so we just disable the blending to prevent possible issues.
+ */
+ entry->ColorBufferBlendEnable =
+ !ctx->Color.Blend[0]._UsesDualSrc || wm_prog_data->dual_src_blend;
+
entry->DestinationBlendFactor = blend_factor(dstRGB);
entry->SourceBlendFactor = blend_factor(srcRGB);
entry->DestinationAlphaBlendFactor = blend_factor(dstA);
_NEW_MULTISAMPLE,
.brw = BRW_NEW_BATCH |
BRW_NEW_BLORP |
+ BRW_NEW_FS_PROG_DATA |
BRW_NEW_STATE_BASE_ADDRESS,
},
.emit = genX(upload_blend_state),
sbe.NumberofSFOutputAttributes = wm_prog_data->num_varying_inputs;
/* _NEW_BUFFERS */
- bool render_to_fbo = _mesa_is_user_fbo(ctx->DrawBuffer);
+ bool flip_y = ctx->DrawBuffer->FlipY;
/* _NEW_POINT
*
* Window coordinates in an FBO are inverted, which means point
* sprite origin must be inverted.
*/
- if ((ctx->Point.SpriteOrigin == GL_LOWER_LEFT) != render_to_fbo)
+ if ((ctx->Point.SpriteOrigin == GL_LOWER_LEFT) == flip_y)
sbe.PointSpriteTextureCoordinateOrigin = LOWERLEFT;
else
sbe.PointSpriteTextureCoordinateOrigin = UPPERLEFT;
for (int i = 0; i < 4; i++) {
struct intel_buffer_object *bufferobj =
intel_buffer_object(xfb_obj->Buffers[i]);
+ uint32_t start = xfb_obj->Offset[i];
+ uint32_t end = ALIGN(start + xfb_obj->Size[i], 4);
+ uint32_t const size = end - start;
- if (!bufferobj) {
+ if (!bufferobj || !size) {
brw_batch_emit(brw, GENX(3DSTATE_SO_BUFFER), sob) {
sob.SOBufferIndex = i;
}
continue;
}
- uint32_t start = xfb_obj->Offset[i];
assert(start % 4 == 0);
- uint32_t end = ALIGN(start + xfb_obj->Size[i], 4);
struct brw_bo *bo =
- intel_bufferobj_buffer(brw, bufferobj, start, end - start, true);
+ intel_bufferobj_buffer(brw, bufferobj, start, size, true);
assert(end <= bo->size);
brw_batch_emit(brw, GENX(3DSTATE_SO_BUFFER), sob) {
sob.SOBufferEnable = true;
sob.StreamOffsetWriteEnable = true;
sob.StreamOutputBufferOffsetAddressEnable = true;
- sob.SOBufferMOCS = mocs_wb;
+ sob.MOCS = mocs_wb;
sob.SurfaceSize = MAX2(xfb_obj->Size[i] / 4, 1) - 1;
sob.StreamOutputBufferOffsetAddress =
*/
ps.VectorMaskEnable = GEN_GEN >= 8;
- ps.SamplerCount =
- DIV_ROUND_UP(CLAMP(stage_state->sampler_count, 0, 16), 4);
+ /* WA_1606682166:
+ * "Incorrect TDL's SSP address shift in SARB for 16:6 & 18:8 modes.
+ * Disable the Sampler state prefetch functionality in the SARB by
+ * programming 0xB000[30] to '1'."
+ */
+ ps.SamplerCount = GEN_GEN == 11 ?
+ 0 : DIV_ROUND_UP(CLAMP(stage_state->sampler_count, 0, 16), 4);
/* BRW_NEW_FS_PROG_DATA */
- ps.BindingTableEntryCount = prog_data->base.binding_table.size_bytes / 4;
+ /* Gen 11 workarounds table #2056 WABTPPrefetchDisable suggests to disable
+ * prefetching of binding tables in A0 and B0 steppings.
+ * TODO: Revisit this workaround on C0 stepping.
+ */
+ ps.BindingTableEntryCount = GEN_GEN == 11 ?
+ 0 :
+ prog_data->base.binding_table.size_bytes / 4;
if (prog_data->base.use_alt_mode)
ps.FloatingPointMode = Alternate;
ps._16PixelDispatchEnable = prog_data->dispatch_16;
ps._32PixelDispatchEnable = prog_data->dispatch_32;
+ /* From the Sky Lake PRM 3DSTATE_PS::32 Pixel Dispatch Enable:
+ *
+ * "When NUM_MULTISAMPLES = 16 or FORCE_SAMPLE_COUNT = 16, SIMD32
+ * Dispatch must not be enabled for PER_PIXEL dispatch mode."
+ *
+ * Since 16x MSAA is first introduced on SKL, we don't need to apply
+ * the workaround on any older hardware.
+ *
+ * BRW_NEW_NUM_SAMPLES
+ */
+ if (GEN_GEN >= 9 && !prog_data->persample_dispatch &&
+ brw->num_samples == 16) {
+ assert(ps._8PixelDispatchEnable || ps._16PixelDispatchEnable);
+ ps._32PixelDispatchEnable = false;
+ }
+
ps.DispatchGRFStartRegisterForConstantSetupData0 =
brw_wm_prog_data_dispatch_grf_start_reg(prog_data, ps, 0);
ps.DispatchGRFStartRegisterForConstantSetupData1 =
: 0),
.brw = BRW_NEW_BATCH |
BRW_NEW_BLORP |
- BRW_NEW_FS_PROG_DATA,
+ BRW_NEW_FS_PROG_DATA |
+ (GEN_GEN >= 9 ? BRW_NEW_NUM_SAMPLES : 0),
},
.emit = genX(upload_ps),
};
.emit = genX(upload_cs_state)
};
+#define GPGPU_DISPATCHDIMX 0x2500
+#define GPGPU_DISPATCHDIMY 0x2504
+#define GPGPU_DISPATCHDIMZ 0x2508
+
+#define MI_PREDICATE_SRC0 0x2400
+#define MI_PREDICATE_SRC1 0x2408
+
+static void
+prepare_indirect_gpgpu_walker(struct brw_context *brw)
+{
+ GLintptr indirect_offset = brw->compute.num_work_groups_offset;
+ struct brw_bo *bo = brw->compute.num_work_groups_bo;
+
+ emit_lrm(brw, GPGPU_DISPATCHDIMX, ro_bo(bo, indirect_offset + 0));
+ emit_lrm(brw, GPGPU_DISPATCHDIMY, ro_bo(bo, indirect_offset + 4));
+ emit_lrm(brw, GPGPU_DISPATCHDIMZ, ro_bo(bo, indirect_offset + 8));
+
+#if GEN_GEN <= 7
+ /* Clear upper 32-bits of SRC0 and all 64-bits of SRC1 */
+ emit_lri(brw, MI_PREDICATE_SRC0 + 4, 0);
+ emit_lri(brw, MI_PREDICATE_SRC1 , 0);
+ emit_lri(brw, MI_PREDICATE_SRC1 + 4, 0);
+
+ /* Load compute_dispatch_indirect_x_size into SRC0 */
+ emit_lrm(brw, MI_PREDICATE_SRC0, ro_bo(bo, indirect_offset + 0));
+
+ /* predicate = (compute_dispatch_indirect_x_size == 0); */
+ brw_batch_emit(brw, GENX(MI_PREDICATE), mip) {
+ mip.LoadOperation = LOAD_LOAD;
+ mip.CombineOperation = COMBINE_SET;
+ mip.CompareOperation = COMPARE_SRCS_EQUAL;
+ }
+
+ /* Load compute_dispatch_indirect_y_size into SRC0 */
+ emit_lrm(brw, MI_PREDICATE_SRC0, ro_bo(bo, indirect_offset + 4));
+
+ /* predicate |= (compute_dispatch_indirect_y_size == 0); */
+ brw_batch_emit(brw, GENX(MI_PREDICATE), mip) {
+ mip.LoadOperation = LOAD_LOAD;
+ mip.CombineOperation = COMBINE_OR;
+ mip.CompareOperation = COMPARE_SRCS_EQUAL;
+ }
+
+ /* Load compute_dispatch_indirect_z_size into SRC0 */
+ emit_lrm(brw, MI_PREDICATE_SRC0, ro_bo(bo, indirect_offset + 8));
+
+ /* predicate |= (compute_dispatch_indirect_z_size == 0); */
+ brw_batch_emit(brw, GENX(MI_PREDICATE), mip) {
+ mip.LoadOperation = LOAD_LOAD;
+ mip.CombineOperation = COMBINE_OR;
+ mip.CompareOperation = COMPARE_SRCS_EQUAL;
+ }
+
+ /* predicate = !predicate; */
+#define COMPARE_FALSE 1
+ brw_batch_emit(brw, GENX(MI_PREDICATE), mip) {
+ mip.LoadOperation = LOAD_LOADINV;
+ mip.CombineOperation = COMBINE_OR;
+ mip.CompareOperation = COMPARE_FALSE;
+ }
+#endif
+}
+
+static void
+genX(emit_gpgpu_walker)(struct brw_context *brw)
+{
+ const struct brw_cs_prog_data *prog_data =
+ brw_cs_prog_data(brw->cs.base.prog_data);
+
+ const GLuint *num_groups = brw->compute.num_work_groups;
+
+ bool indirect = brw->compute.num_work_groups_bo != NULL;
+ if (indirect)
+ prepare_indirect_gpgpu_walker(brw);
+
+ const unsigned simd_size = prog_data->simd_size;
+ unsigned group_size = prog_data->local_size[0] *
+ prog_data->local_size[1] * prog_data->local_size[2];
+
+ uint32_t right_mask = 0xffffffffu >> (32 - simd_size);
+ const unsigned right_non_aligned = group_size & (simd_size - 1);
+ if (right_non_aligned != 0)
+ right_mask >>= (simd_size - right_non_aligned);
+
+ brw_batch_emit(brw, GENX(GPGPU_WALKER), ggw) {
+ ggw.IndirectParameterEnable = indirect;
+ ggw.PredicateEnable = GEN_GEN <= 7 && indirect;
+ ggw.SIMDSize = prog_data->simd_size / 16;
+ ggw.ThreadDepthCounterMaximum = 0;
+ ggw.ThreadHeightCounterMaximum = 0;
+ ggw.ThreadWidthCounterMaximum = prog_data->threads - 1;
+ ggw.ThreadGroupIDXDimension = num_groups[0];
+ ggw.ThreadGroupIDYDimension = num_groups[1];
+ ggw.ThreadGroupIDZDimension = num_groups[2];
+ ggw.RightExecutionMask = right_mask;
+ ggw.BottomExecutionMask = 0xffffffff;
+ }
+
+ brw_batch_emit(brw, GENX(MEDIA_STATE_FLUSH), msf);
+}
+
#endif
/* ---------------------------------------------------------------------- */
const struct gl_context *ctx = &brw->ctx;
/* _NEW_BUFFERS */
- const bool render_to_fbo = _mesa_is_user_fbo(ctx->DrawBuffer);
+ const bool flip_y = ctx->DrawBuffer->FlipY;
/* _NEW_POLYGON */
const struct gl_polygon_attrib *polygon = &ctx->Polygon;
const struct gl_point_attrib *point = &ctx->Point;
brw_batch_emit(brw, GENX(3DSTATE_RASTER), raster) {
- if (brw->polygon_front_bit == render_to_fbo)
+ if (brw->polygon_front_bit != flip_y)
raster.FrontWinding = CounterClockwise;
if (polygon->CullFlag) {
raster.ScissorRectangleEnable = ctx->Scissor.EnableFlags;
/* _NEW_TRANSFORM */
- if (!ctx->Transform.DepthClamp) {
+#if GEN_GEN < 9
+ if (!(ctx->Transform.DepthClampNear &&
+ ctx->Transform.DepthClampFar))
+ raster.ViewportZClipTestEnable = true;
+#endif
+
#if GEN_GEN >= 9
- raster.ViewportZFarClipTestEnable = true;
+ if (!ctx->Transform.DepthClampNear)
raster.ViewportZNearClipTestEnable = true;
-#else
- raster.ViewportZClipTestEnable = true;
+
+ if (!ctx->Transform.DepthClampFar)
+ raster.ViewportZFarClipTestEnable = true;
#endif
- }
/* BRW_NEW_CONSERVATIVE_RASTERIZATION */
#if GEN_GEN >= 9
dstA = fix_dual_blend_alpha_to_one(dstA);
}
- pb.ColorBufferBlendEnable = true;
+ /* BRW_NEW_FS_PROG_DATA */
+ const struct brw_wm_prog_data *wm_prog_data =
+ brw_wm_prog_data(brw->wm.base.prog_data);
+
+ /* The Dual Source Blending documentation says:
+ *
+ * "If SRC1 is included in a src/dst blend factor and
+ * a DualSource RT Write message is not used, results
+ * are UNDEFINED. (This reflects the same restriction in DX APIs,
+ * where undefined results are produced if “o1” is not written
+ * by a PS – there are no default values defined).
+ * If SRC1 is not included in a src/dst blend factor,
+ * dual source blending must be disabled."
+ *
+ * There is no way to gracefully fix this undefined situation
+ * so we just disable the blending to prevent possible issues.
+ */
+ pb.ColorBufferBlendEnable =
+ !color->Blend[0]._UsesDualSrc || wm_prog_data->dual_src_blend;
pb.SourceAlphaBlendFactor = brw_translate_blend_factor(srcA);
pb.DestinationAlphaBlendFactor = brw_translate_blend_factor(dstA);
pb.SourceBlendFactor = brw_translate_blend_factor(srcRGB);
_NEW_MULTISAMPLE,
.brw = BRW_NEW_BLORP |
BRW_NEW_CONTEXT |
- BRW_NEW_FRAGMENT_PROGRAM,
+ BRW_NEW_FRAGMENT_PROGRAM |
+ BRW_NEW_FS_PROG_DATA,
},
.emit = genX(upload_ps_blend)
};
compute_atoms, ARRAY_SIZE(compute_atoms));
brw->vtbl.emit_mi_report_perf_count = genX(emit_mi_report_perf_count);
+ brw->vtbl.emit_compute_walker = genX(emit_gpgpu_walker);
#endif
}