+ if (params->wm_prog_data) {
+ blend_state_offset = blorp_emit_blend_state(batch, params);
+ }
+ color_calc_state_offset = blorp_emit_color_calc_state(batch, params);
+ depth_stencil_state_offset = blorp_emit_depth_stencil_state(batch, params);
+
+#if GEN_GEN == 6
+ /* 3DSTATE_CC_STATE_POINTERS
+ *
+ * The pointer offsets are relative to
+ * CMD_STATE_BASE_ADDRESS.DynamicStateBaseAddress.
+ *
+ * The HiZ op doesn't use BLEND_STATE or COLOR_CALC_STATE.
+ *
+ * The dynamic state emit helpers emit their own STATE_POINTERS packets on
+ * gen7+. However, on gen6 and earlier, they're all lumpped together in
+ * one CC_STATE_POINTERS packet so we have to emit that here.
+ */
+ blorp_emit(batch, GENX(3DSTATE_CC_STATE_POINTERS), cc) {
+ cc.BLEND_STATEChange = true;
+ cc.ColorCalcStatePointerValid = true;
+ cc.DEPTH_STENCIL_STATEChange = true;
+ cc.PointertoBLEND_STATE = blend_state_offset;
+ cc.ColorCalcStatePointer = color_calc_state_offset;
+ cc.PointertoDEPTH_STENCIL_STATE = depth_stencil_state_offset;
+ }
+#else
+ (void)blend_state_offset;
+ (void)color_calc_state_offset;
+ (void)depth_stencil_state_offset;
+#endif
+
+#if GEN_GEN >= 12
+ blorp_emit(batch, GENX(3DSTATE_CONSTANT_ALL), pc) {
+ /* Update empty push constants for all stages (bitmask = 11111b) */
+ pc.ShaderUpdateEnable = 0x1f;
+ }
+#else
+ blorp_emit(batch, GENX(3DSTATE_CONSTANT_VS), vs);
+#if GEN_GEN >= 7
+ blorp_emit(batch, GENX(3DSTATE_CONSTANT_HS), hs);
+ blorp_emit(batch, GENX(3DSTATE_CONSTANT_DS), DS);
+#endif
+ blorp_emit(batch, GENX(3DSTATE_CONSTANT_GS), gs);
+ blorp_emit(batch, GENX(3DSTATE_CONSTANT_PS), ps);
+#endif
+
+ if (params->src.enabled)
+ blorp_emit_sampler_state(batch);
+
+ blorp_emit_3dstate_multisample(batch, params);
+
+ blorp_emit(batch, GENX(3DSTATE_SAMPLE_MASK), mask) {
+ mask.SampleMask = (1 << params->num_samples) - 1;
+ }
+
+ /* From the BSpec, 3D Pipeline > Geometry > Vertex Shader > State,
+ * 3DSTATE_VS, Dword 5.0 "VS Function Enable":
+ *
+ * [DevSNB] A pipeline flush must be programmed prior to a
+ * 3DSTATE_VS command that causes the VS Function Enable to
+ * toggle. Pipeline flush can be executed by sending a PIPE_CONTROL
+ * command with CS stall bit set and a post sync operation.
+ *
+ * We've already done one at the start of the BLORP operation.
+ */
+ blorp_emit_vs_config(batch, params);
+#if GEN_GEN >= 7
+ blorp_emit(batch, GENX(3DSTATE_HS), hs);
+ blorp_emit(batch, GENX(3DSTATE_TE), te);
+ blorp_emit(batch, GENX(3DSTATE_DS), DS);
+ blorp_emit(batch, GENX(3DSTATE_STREAMOUT), so);
+#endif
+ blorp_emit(batch, GENX(3DSTATE_GS), gs);
+
+ blorp_emit(batch, GENX(3DSTATE_CLIP), clip) {
+ clip.PerspectiveDivideDisable = true;
+ }
+
+ blorp_emit_sf_config(batch, params);
+ blorp_emit_ps_config(batch, params);
+
+ blorp_emit_cc_viewport(batch);
+}
+
+/******** This is the end of the pipeline setup code ********/
+
+#endif /* GEN_GEN >= 6 */
+
+#if GEN_GEN >= 7
+static void
+blorp_emit_memcpy(struct blorp_batch *batch,
+ struct blorp_address dst,
+ struct blorp_address src,
+ uint32_t size)
+{
+ assert(size % 4 == 0);
+
+ for (unsigned dw = 0; dw < size; dw += 4) {
+#if GEN_GEN >= 8
+ blorp_emit(batch, GENX(MI_COPY_MEM_MEM), cp) {
+ cp.DestinationMemoryAddress = dst;
+ cp.SourceMemoryAddress = src;
+ }
+#else
+ /* IVB does not have a general purpose register for command streamer
+ * commands. Therefore, we use an alternate temporary register.
+ */
+#define BLORP_TEMP_REG 0x2440 /* GEN7_3DPRIM_BASE_VERTEX */
+ blorp_emit(batch, GENX(MI_LOAD_REGISTER_MEM), load) {
+ load.RegisterAddress = BLORP_TEMP_REG;
+ load.MemoryAddress = src;
+ }
+ blorp_emit(batch, GENX(MI_STORE_REGISTER_MEM), store) {
+ store.RegisterAddress = BLORP_TEMP_REG;
+ store.MemoryAddress = dst;
+ }
+#undef BLORP_TEMP_REG
+#endif
+ dst.offset += 4;
+ src.offset += 4;
+ }
+}
+#endif
+
+static void
+blorp_emit_surface_state(struct blorp_batch *batch,
+ const struct brw_blorp_surface_info *surface,
+ enum isl_aux_op aux_op,
+ void *state, uint32_t state_offset,
+ const bool color_write_disables[4],
+ bool is_render_target)
+{
+ const struct isl_device *isl_dev = batch->blorp->isl_dev;
+ struct isl_surf surf = surface->surf;
+
+ if (surf.dim == ISL_SURF_DIM_1D &&
+ surf.dim_layout == ISL_DIM_LAYOUT_GEN4_2D) {
+ assert(surf.logical_level0_px.height == 1);
+ surf.dim = ISL_SURF_DIM_2D;
+ }
+
+ /* Blorp doesn't support HiZ in any of the blit or slow-clear paths */
+ assert(!isl_aux_usage_has_hiz(surface->aux_usage));
+ enum isl_aux_usage aux_usage = surface->aux_usage;
+
+ isl_channel_mask_t write_disable_mask = 0;
+ if (is_render_target && GEN_GEN <= 5) {
+ if (color_write_disables[0])
+ write_disable_mask |= ISL_CHANNEL_RED_BIT;
+ if (color_write_disables[1])
+ write_disable_mask |= ISL_CHANNEL_GREEN_BIT;
+ if (color_write_disables[2])
+ write_disable_mask |= ISL_CHANNEL_BLUE_BIT;
+ if (color_write_disables[3])
+ write_disable_mask |= ISL_CHANNEL_ALPHA_BIT;
+ }
+
+ const bool use_clear_address =
+ GEN_GEN >= 10 && (surface->clear_color_addr.buffer != NULL);
+
+ isl_surf_fill_state(batch->blorp->isl_dev, state,
+ .surf = &surf, .view = &surface->view,
+ .aux_surf = &surface->aux_surf, .aux_usage = aux_usage,
+ .address =
+ blorp_get_surface_address(batch, surface->addr),
+ .aux_address = aux_usage == ISL_AUX_USAGE_NONE ? 0 :
+ blorp_get_surface_address(batch, surface->aux_addr),
+ .clear_address = !use_clear_address ? 0 :
+ blorp_get_surface_address(batch,
+ surface->clear_color_addr),
+ .mocs = surface->addr.mocs,
+ .clear_color = surface->clear_color,
+ .use_clear_address = use_clear_address,
+ .write_disables = write_disable_mask);
+
+ blorp_surface_reloc(batch, state_offset + isl_dev->ss.addr_offset,
+ surface->addr, 0);