1/* -*- c-basic-offset: 4 -*- */ 2/* 3 * Copyright © 2006 Intel Corporation 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the "Software"), 7 * to deal in the Software without restriction, including without limitation 8 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 * and/or sell copies of the Software, and to permit persons to whom the 10 * Software is furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice (including the next 13 * paragraph) shall be included in all copies or substantial portions of the 14 * Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 * SOFTWARE. 23 * 24 * Authors: 25 * Eric Anholt <eric@anholt.net> 26 * 27 */ 28 29#ifdef HAVE_CONFIG_H 30#include "config.h" 31#endif 32 33#include <assert.h> 34#include <stdlib.h> 35#include <errno.h> 36 37#include "xorg-server.h" 38#include "xf86.h" 39#include "intel.h" 40#include "i830_reg.h" 41#include "i915_drm.h" 42#include "i965_reg.h" 43 44#include "intel_uxa.h" 45 46#define DUMP_BATCHBUFFERS NULL // "/tmp/i915-batchbuffers.dump" 47 48static void intel_end_vertex(intel_screen_private *intel) 49{ 50 if (intel->vertex_bo) { 51 if (intel->vertex_used) { 52 dri_bo_subdata(intel->vertex_bo, 0, intel->vertex_used*4, intel->vertex_ptr); 53 intel->vertex_used = 0; 54 } 55 56 dri_bo_unreference(intel->vertex_bo); 57 intel->vertex_bo = NULL; 58 } 59 60 intel->vertex_id = 0; 61} 62 63void intel_next_vertex(intel_screen_private *intel) 64{ 65 intel_end_vertex(intel); 66 67 intel->vertex_bo = 68 dri_bo_alloc(intel->bufmgr, "vertex", sizeof (intel->vertex_ptr), 4096); 69} 70 71static dri_bo *bo_alloc(ScrnInfoPtr scrn) 72{ 73 intel_screen_private *intel = intel_get_screen_private(scrn); 74 int size = 4 * 4096; 75 /* The 865 has issues with larger-than-page-sized batch buffers. */ 76 if (IS_I865G(intel)) 77 size = 4096; 78 return dri_bo_alloc(intel->bufmgr, "batch", size, 4096); 79} 80 81static void intel_next_batch(ScrnInfoPtr scrn, int mode) 82{ 83 intel_screen_private *intel = intel_get_screen_private(scrn); 84 dri_bo *tmp; 85 86 drm_intel_gem_bo_clear_relocs(intel->batch_bo, 0); 87 88 tmp = intel->last_batch_bo[mode]; 89 intel->last_batch_bo[mode] = intel->batch_bo; 90 intel->batch_bo = tmp; 91 92 intel->batch_used = 0; 93 94 /* We don't know when another client has executed, so we have 95 * to reinitialize our 3D state per batch. 96 */ 97 intel->last_3d = LAST_3D_OTHER; 98} 99 100void intel_batch_init(ScrnInfoPtr scrn) 101{ 102 intel_screen_private *intel = intel_get_screen_private(scrn); 103 104 intel->batch_emit_start = 0; 105 intel->batch_emitting = 0; 106 intel->vertex_id = 0; 107 108 intel->last_batch_bo[0] = bo_alloc(scrn); 109 intel->last_batch_bo[1] = bo_alloc(scrn); 110 111 intel->batch_bo = bo_alloc(scrn); 112 intel->batch_used = 0; 113 intel->last_3d = LAST_3D_OTHER; 114} 115 116void intel_batch_teardown(ScrnInfoPtr scrn) 117{ 118 intel_screen_private *intel = intel_get_screen_private(scrn); 119 int i; 120 121 for (i = 0; i < ARRAY_SIZE(intel->last_batch_bo); i++) { 122 if (intel->last_batch_bo[i] != NULL) { 123 dri_bo_unreference(intel->last_batch_bo[i]); 124 intel->last_batch_bo[i] = NULL; 125 } 126 } 127 128 if (intel->batch_bo != NULL) { 129 dri_bo_unreference(intel->batch_bo); 130 intel->batch_bo = NULL; 131 } 132 133 if (intel->vertex_bo) { 134 dri_bo_unreference(intel->vertex_bo); 135 intel->vertex_bo = NULL; 136 } 137 138 while (!list_is_empty(&intel->batch_pixmaps)) 139 list_del(intel->batch_pixmaps.next); 140} 141 142static void intel_batch_do_flush(ScrnInfoPtr scrn) 143{ 144 intel_screen_private *intel = intel_get_screen_private(scrn); 145 struct intel_uxa_pixmap *priv; 146 147 list_for_each_entry(priv, &intel->batch_pixmaps, batch) 148 priv->dirty = 0; 149} 150 151static void intel_emit_post_sync_nonzero_flush(ScrnInfoPtr scrn) 152{ 153 intel_screen_private *intel = intel_get_screen_private(scrn); 154 155 /* keep this entire sequence of 3 PIPE_CONTROL cmds in one batch to 156 * avoid upsetting the gpu. */ 157 BEGIN_BATCH(3*4); 158 OUT_BATCH(BRW_PIPE_CONTROL | (4 - 2)); 159 OUT_BATCH(BRW_PIPE_CONTROL_CS_STALL | 160 BRW_PIPE_CONTROL_STALL_AT_SCOREBOARD); 161 OUT_BATCH(0); /* address */ 162 OUT_BATCH(0); /* write data */ 163 164 OUT_BATCH(BRW_PIPE_CONTROL | (4 - 2)); 165 OUT_BATCH(BRW_PIPE_CONTROL_WRITE_QWORD); 166 OUT_RELOC(intel->wa_scratch_bo, 167 I915_GEM_DOMAIN_INSTRUCTION, I915_GEM_DOMAIN_INSTRUCTION, 0); 168 OUT_BATCH(0); /* write data */ 169 170 /* now finally the _real flush */ 171 OUT_BATCH(BRW_PIPE_CONTROL | (4 - 2)); 172 OUT_BATCH(BRW_PIPE_CONTROL_WC_FLUSH | 173 BRW_PIPE_CONTROL_TC_FLUSH | 174 BRW_PIPE_CONTROL_NOWRITE); 175 OUT_BATCH(0); /* write address */ 176 OUT_BATCH(0); /* write data */ 177 ADVANCE_BATCH(); 178} 179 180void intel_batch_emit_flush(ScrnInfoPtr scrn) 181{ 182 intel_screen_private *intel = intel_get_screen_private(scrn); 183 int flags; 184 185 assert (!intel->in_batch_atomic); 186 187 /* Big hammer, look to the pipelined flushes in future. */ 188 if ((INTEL_INFO(intel)->gen >= 0100)) { 189 /* Only BLT supported */ 190 BEGIN_BATCH_BLT(4); 191 OUT_BATCH(MI_FLUSH_DW | 2); 192 OUT_BATCH(0); /* address low */ 193 OUT_BATCH(0); /* address high */ 194 OUT_BATCH(0); /* dword data */ 195 ADVANCE_BATCH(); 196 } else if ((INTEL_INFO(intel)->gen >= 060)) { 197 if (intel->current_batch == BLT_BATCH) { 198 BEGIN_BATCH_BLT(4); 199 OUT_BATCH(MI_FLUSH_DW | 2); 200 OUT_BATCH(0); /* address */ 201 OUT_BATCH(0); /* qword low */ 202 OUT_BATCH(0); /* qword high */ 203 ADVANCE_BATCH(); 204 } else { 205 if ((INTEL_INFO(intel)->gen == 060)) { 206 /* HW-Workaround for Sandybdrige */ 207 intel_emit_post_sync_nonzero_flush(scrn); 208 } else { 209 BEGIN_BATCH(4); 210 OUT_BATCH(BRW_PIPE_CONTROL | (4 - 2)); 211 OUT_BATCH(BRW_PIPE_CONTROL_WC_FLUSH | 212 BRW_PIPE_CONTROL_TC_FLUSH | 213 BRW_PIPE_CONTROL_NOWRITE); 214 OUT_BATCH(0); /* write address */ 215 OUT_BATCH(0); /* write data */ 216 ADVANCE_BATCH(); 217 } 218 } 219 } else { 220 flags = MI_WRITE_DIRTY_STATE | MI_INVALIDATE_MAP_CACHE; 221 if (INTEL_INFO(intel)->gen >= 040) 222 flags = 0; 223 224 BEGIN_BATCH(1); 225 OUT_BATCH(MI_FLUSH | flags); 226 ADVANCE_BATCH(); 227 } 228 intel_batch_do_flush(scrn); 229} 230 231void intel_batch_submit(ScrnInfoPtr scrn) 232{ 233 intel_screen_private *intel = intel_get_screen_private(scrn); 234 int ret; 235 236 assert (!intel->in_batch_atomic); 237 238 if (intel->vertex_flush) 239 intel->vertex_flush(intel); 240 intel_end_vertex(intel); 241 242 if (intel->batch_flush) 243 intel->batch_flush(intel); 244 245 if (intel->batch_used == 0) 246 return; 247 248 /* Mark the end of the batchbuffer. */ 249 OUT_BATCH(MI_BATCH_BUFFER_END); 250 /* Emit a padding dword if we aren't going to be quad-word aligned. */ 251 if (intel->batch_used & 1) 252 OUT_BATCH(MI_NOOP); 253 254 if (DUMP_BATCHBUFFERS) { 255 FILE *file = fopen(DUMP_BATCHBUFFERS, "a"); 256 if (file) { 257 fwrite (intel->batch_ptr, intel->batch_used*4, 1, file); 258 fclose(file); 259 } 260 } 261 262 ret = dri_bo_subdata(intel->batch_bo, 0, intel->batch_used*4, intel->batch_ptr); 263 if (ret == 0) { 264 ret = drm_intel_bo_mrb_exec(intel->batch_bo, 265 intel->batch_used*4, 266 NULL, 0, 0xffffffff, 267 (HAS_BLT(intel) ? 268 intel->current_batch: 269 I915_EXEC_DEFAULT)); 270 } 271 272 if (ret != 0) { 273 static int once; 274 if (!once) { 275 if (ret == -EIO) { 276 /* The GPU has hung and unlikely to recover by this point. */ 277 xf86DrvMsg(scrn->scrnIndex, X_ERROR, "Detected a hung GPU, disabling acceleration.\n"); 278 xf86DrvMsg(scrn->scrnIndex, X_ERROR, "When reporting this, please include i915_error_state from debugfs and the full dmesg.\n"); 279 } else { 280 /* The driver is broken. */ 281 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 282 "Failed to submit batch buffer, expect rendering corruption: %s.\n ", 283 strerror(-ret)); 284 } 285 uxa_set_force_fallback(xf86ScrnToScreen(scrn), TRUE); 286 intel->force_fallback = TRUE; 287 once = 1; 288 } 289 } 290 291 while (!list_is_empty(&intel->batch_pixmaps)) { 292 struct intel_uxa_pixmap *entry; 293 294 entry = list_first_entry(&intel->batch_pixmaps, 295 struct intel_uxa_pixmap, 296 batch); 297 298 entry->busy = -1; 299 entry->dirty = 0; 300 list_del(&entry->batch); 301 } 302 303 if (intel->debug_flush & DEBUG_FLUSH_WAIT) 304 drm_intel_bo_wait_rendering(intel->batch_bo); 305 306 intel_next_batch(scrn, intel->current_batch == I915_EXEC_BLT); 307 308 if (intel->batch_commit_notify) 309 intel->batch_commit_notify(intel); 310 311 intel->current_batch = 0; 312} 313 314void intel_uxa_debug_flush(ScrnInfoPtr scrn) 315{ 316 intel_screen_private *intel = intel_get_screen_private(scrn); 317 318 if (intel->debug_flush & DEBUG_FLUSH_CACHES) 319 intel_batch_emit_flush(scrn); 320 321 if (intel->debug_flush & DEBUG_FLUSH_BATCHES) 322 intel_batch_submit(scrn); 323} 324