intel_batchbuffer.c revision 03b705cf
103b705cfSriastradh/* -*- c-basic-offset: 4 -*- */ 203b705cfSriastradh/* 303b705cfSriastradh * Copyright © 2006 Intel Corporation 403b705cfSriastradh * 503b705cfSriastradh * Permission is hereby granted, free of charge, to any person obtaining a 603b705cfSriastradh * copy of this software and associated documentation files (the "Software"), 703b705cfSriastradh * to deal in the Software without restriction, including without limitation 803b705cfSriastradh * the rights to use, copy, modify, merge, publish, distribute, sublicense, 903b705cfSriastradh * and/or sell copies of the Software, and to permit persons to whom the 1003b705cfSriastradh * Software is furnished to do so, subject to the following conditions: 1103b705cfSriastradh * 1203b705cfSriastradh * The above copyright notice and this permission notice (including the next 1303b705cfSriastradh * paragraph) shall be included in all copies or substantial portions of the 1403b705cfSriastradh * Software. 1503b705cfSriastradh * 1603b705cfSriastradh * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1703b705cfSriastradh * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1803b705cfSriastradh * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1903b705cfSriastradh * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 2003b705cfSriastradh * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 2103b705cfSriastradh * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 2203b705cfSriastradh * SOFTWARE. 2303b705cfSriastradh * 2403b705cfSriastradh * Authors: 2503b705cfSriastradh * Eric Anholt <eric@anholt.net> 2603b705cfSriastradh * 2703b705cfSriastradh */ 2803b705cfSriastradh 2903b705cfSriastradh#ifdef HAVE_CONFIG_H 3003b705cfSriastradh#include "config.h" 3103b705cfSriastradh#endif 3203b705cfSriastradh 3303b705cfSriastradh#include <assert.h> 3403b705cfSriastradh#include <stdlib.h> 3503b705cfSriastradh#include <errno.h> 3603b705cfSriastradh 3703b705cfSriastradh#include "xf86.h" 3803b705cfSriastradh#include "intel.h" 3903b705cfSriastradh#include "i830_reg.h" 4003b705cfSriastradh#include "i915_drm.h" 4103b705cfSriastradh#include "i965_reg.h" 4203b705cfSriastradh 4303b705cfSriastradh#include "uxa.h" 4403b705cfSriastradh 4503b705cfSriastradh#define DUMP_BATCHBUFFERS NULL // "/tmp/i915-batchbuffers.dump" 4603b705cfSriastradh 4703b705cfSriastradhstatic void intel_end_vertex(intel_screen_private *intel) 4803b705cfSriastradh{ 4903b705cfSriastradh if (intel->vertex_bo) { 5003b705cfSriastradh if (intel->vertex_used) { 5103b705cfSriastradh dri_bo_subdata(intel->vertex_bo, 0, intel->vertex_used*4, intel->vertex_ptr); 5203b705cfSriastradh intel->vertex_used = 0; 5303b705cfSriastradh } 5403b705cfSriastradh 5503b705cfSriastradh dri_bo_unreference(intel->vertex_bo); 5603b705cfSriastradh intel->vertex_bo = NULL; 5703b705cfSriastradh } 5803b705cfSriastradh 5903b705cfSriastradh intel->vertex_id = 0; 6003b705cfSriastradh} 6103b705cfSriastradh 6203b705cfSriastradhvoid intel_next_vertex(intel_screen_private *intel) 6303b705cfSriastradh{ 6403b705cfSriastradh intel_end_vertex(intel); 6503b705cfSriastradh 6603b705cfSriastradh intel->vertex_bo = 6703b705cfSriastradh dri_bo_alloc(intel->bufmgr, "vertex", sizeof (intel->vertex_ptr), 4096); 6803b705cfSriastradh} 6903b705cfSriastradh 7003b705cfSriastradhstatic dri_bo *bo_alloc(ScrnInfoPtr scrn) 7103b705cfSriastradh{ 7203b705cfSriastradh intel_screen_private *intel = intel_get_screen_private(scrn); 7303b705cfSriastradh int size = 4 * 4096; 7403b705cfSriastradh /* The 865 has issues with larger-than-page-sized batch buffers. */ 7503b705cfSriastradh if (IS_I865G(intel)) 7603b705cfSriastradh size = 4096; 7703b705cfSriastradh return dri_bo_alloc(intel->bufmgr, "batch", size, 4096); 7803b705cfSriastradh} 7903b705cfSriastradh 8003b705cfSriastradhstatic void intel_next_batch(ScrnInfoPtr scrn, int mode) 8103b705cfSriastradh{ 8203b705cfSriastradh intel_screen_private *intel = intel_get_screen_private(scrn); 8303b705cfSriastradh dri_bo *tmp; 8403b705cfSriastradh 8503b705cfSriastradh drm_intel_gem_bo_clear_relocs(intel->batch_bo, 0); 8603b705cfSriastradh 8703b705cfSriastradh tmp = intel->last_batch_bo[mode]; 8803b705cfSriastradh intel->last_batch_bo[mode] = intel->batch_bo; 8903b705cfSriastradh intel->batch_bo = tmp; 9003b705cfSriastradh 9103b705cfSriastradh intel->batch_used = 0; 9203b705cfSriastradh 9303b705cfSriastradh /* We don't know when another client has executed, so we have 9403b705cfSriastradh * to reinitialize our 3D state per batch. 9503b705cfSriastradh */ 9603b705cfSriastradh intel->last_3d = LAST_3D_OTHER; 9703b705cfSriastradh} 9803b705cfSriastradh 9903b705cfSriastradhvoid intel_batch_init(ScrnInfoPtr scrn) 10003b705cfSriastradh{ 10103b705cfSriastradh intel_screen_private *intel = intel_get_screen_private(scrn); 10203b705cfSriastradh 10303b705cfSriastradh intel->batch_emit_start = 0; 10403b705cfSriastradh intel->batch_emitting = 0; 10503b705cfSriastradh intel->vertex_id = 0; 10603b705cfSriastradh 10703b705cfSriastradh intel->last_batch_bo[0] = bo_alloc(scrn); 10803b705cfSriastradh intel->last_batch_bo[1] = bo_alloc(scrn); 10903b705cfSriastradh 11003b705cfSriastradh intel->batch_bo = bo_alloc(scrn); 11103b705cfSriastradh intel->batch_used = 0; 11203b705cfSriastradh intel->last_3d = LAST_3D_OTHER; 11303b705cfSriastradh} 11403b705cfSriastradh 11503b705cfSriastradhvoid intel_batch_teardown(ScrnInfoPtr scrn) 11603b705cfSriastradh{ 11703b705cfSriastradh intel_screen_private *intel = intel_get_screen_private(scrn); 11803b705cfSriastradh int i; 11903b705cfSriastradh 12003b705cfSriastradh for (i = 0; i < ARRAY_SIZE(intel->last_batch_bo); i++) { 12103b705cfSriastradh if (intel->last_batch_bo[i] != NULL) { 12203b705cfSriastradh dri_bo_unreference(intel->last_batch_bo[i]); 12303b705cfSriastradh intel->last_batch_bo[i] = NULL; 12403b705cfSriastradh } 12503b705cfSriastradh } 12603b705cfSriastradh 12703b705cfSriastradh if (intel->batch_bo != NULL) { 12803b705cfSriastradh dri_bo_unreference(intel->batch_bo); 12903b705cfSriastradh intel->batch_bo = NULL; 13003b705cfSriastradh } 13103b705cfSriastradh 13203b705cfSriastradh if (intel->vertex_bo) { 13303b705cfSriastradh dri_bo_unreference(intel->vertex_bo); 13403b705cfSriastradh intel->vertex_bo = NULL; 13503b705cfSriastradh } 13603b705cfSriastradh 13703b705cfSriastradh while (!list_is_empty(&intel->batch_pixmaps)) 13803b705cfSriastradh list_del(intel->batch_pixmaps.next); 13903b705cfSriastradh} 14003b705cfSriastradh 14103b705cfSriastradhstatic void intel_batch_do_flush(ScrnInfoPtr scrn) 14203b705cfSriastradh{ 14303b705cfSriastradh intel_screen_private *intel = intel_get_screen_private(scrn); 14403b705cfSriastradh struct intel_pixmap *priv; 14503b705cfSriastradh 14603b705cfSriastradh list_for_each_entry(priv, &intel->batch_pixmaps, batch) 14703b705cfSriastradh priv->dirty = 0; 14803b705cfSriastradh} 14903b705cfSriastradh 15003b705cfSriastradhstatic void intel_emit_post_sync_nonzero_flush(ScrnInfoPtr scrn) 15103b705cfSriastradh{ 15203b705cfSriastradh intel_screen_private *intel = intel_get_screen_private(scrn); 15303b705cfSriastradh 15403b705cfSriastradh /* keep this entire sequence of 3 PIPE_CONTROL cmds in one batch to 15503b705cfSriastradh * avoid upsetting the gpu. */ 15603b705cfSriastradh BEGIN_BATCH(3*4); 15703b705cfSriastradh OUT_BATCH(BRW_PIPE_CONTROL | (4 - 2)); 15803b705cfSriastradh OUT_BATCH(BRW_PIPE_CONTROL_CS_STALL | 15903b705cfSriastradh BRW_PIPE_CONTROL_STALL_AT_SCOREBOARD); 16003b705cfSriastradh OUT_BATCH(0); /* address */ 16103b705cfSriastradh OUT_BATCH(0); /* write data */ 16203b705cfSriastradh 16303b705cfSriastradh OUT_BATCH(BRW_PIPE_CONTROL | (4 - 2)); 16403b705cfSriastradh OUT_BATCH(BRW_PIPE_CONTROL_WRITE_QWORD); 16503b705cfSriastradh OUT_RELOC(intel->wa_scratch_bo, 16603b705cfSriastradh I915_GEM_DOMAIN_INSTRUCTION, I915_GEM_DOMAIN_INSTRUCTION, 0); 16703b705cfSriastradh OUT_BATCH(0); /* write data */ 16803b705cfSriastradh 16903b705cfSriastradh /* now finally the _real flush */ 17003b705cfSriastradh OUT_BATCH(BRW_PIPE_CONTROL | (4 - 2)); 17103b705cfSriastradh OUT_BATCH(BRW_PIPE_CONTROL_WC_FLUSH | 17203b705cfSriastradh BRW_PIPE_CONTROL_TC_FLUSH | 17303b705cfSriastradh BRW_PIPE_CONTROL_NOWRITE); 17403b705cfSriastradh OUT_BATCH(0); /* write address */ 17503b705cfSriastradh OUT_BATCH(0); /* write data */ 17603b705cfSriastradh ADVANCE_BATCH(); 17703b705cfSriastradh} 17803b705cfSriastradh 17903b705cfSriastradhvoid intel_batch_emit_flush(ScrnInfoPtr scrn) 18003b705cfSriastradh{ 18103b705cfSriastradh intel_screen_private *intel = intel_get_screen_private(scrn); 18203b705cfSriastradh int flags; 18303b705cfSriastradh 18403b705cfSriastradh assert (!intel->in_batch_atomic); 18503b705cfSriastradh 18603b705cfSriastradh /* Big hammer, look to the pipelined flushes in future. */ 18703b705cfSriastradh if ((INTEL_INFO(intel)->gen >= 060)) { 18803b705cfSriastradh if (intel->current_batch == BLT_BATCH) { 18903b705cfSriastradh BEGIN_BATCH_BLT(4); 19003b705cfSriastradh OUT_BATCH(MI_FLUSH_DW | 2); 19103b705cfSriastradh OUT_BATCH(0); 19203b705cfSriastradh OUT_BATCH(0); 19303b705cfSriastradh OUT_BATCH(0); 19403b705cfSriastradh ADVANCE_BATCH(); 19503b705cfSriastradh } else { 19603b705cfSriastradh if ((INTEL_INFO(intel)->gen == 060)) { 19703b705cfSriastradh /* HW-Workaround for Sandybdrige */ 19803b705cfSriastradh intel_emit_post_sync_nonzero_flush(scrn); 19903b705cfSriastradh } else { 20003b705cfSriastradh BEGIN_BATCH(4); 20103b705cfSriastradh OUT_BATCH(BRW_PIPE_CONTROL | (4 - 2)); 20203b705cfSriastradh OUT_BATCH(BRW_PIPE_CONTROL_WC_FLUSH | 20303b705cfSriastradh BRW_PIPE_CONTROL_TC_FLUSH | 20403b705cfSriastradh BRW_PIPE_CONTROL_NOWRITE); 20503b705cfSriastradh OUT_BATCH(0); /* write address */ 20603b705cfSriastradh OUT_BATCH(0); /* write data */ 20703b705cfSriastradh ADVANCE_BATCH(); 20803b705cfSriastradh } 20903b705cfSriastradh } 21003b705cfSriastradh } else { 21103b705cfSriastradh flags = MI_WRITE_DIRTY_STATE | MI_INVALIDATE_MAP_CACHE; 21203b705cfSriastradh if (INTEL_INFO(intel)->gen >= 040) 21303b705cfSriastradh flags = 0; 21403b705cfSriastradh 21503b705cfSriastradh BEGIN_BATCH(1); 21603b705cfSriastradh OUT_BATCH(MI_FLUSH | flags); 21703b705cfSriastradh ADVANCE_BATCH(); 21803b705cfSriastradh } 21903b705cfSriastradh intel_batch_do_flush(scrn); 22003b705cfSriastradh} 22103b705cfSriastradh 22203b705cfSriastradhvoid intel_batch_submit(ScrnInfoPtr scrn) 22303b705cfSriastradh{ 22403b705cfSriastradh intel_screen_private *intel = intel_get_screen_private(scrn); 22503b705cfSriastradh int ret; 22603b705cfSriastradh 22703b705cfSriastradh assert (!intel->in_batch_atomic); 22803b705cfSriastradh 22903b705cfSriastradh if (intel->vertex_flush) 23003b705cfSriastradh intel->vertex_flush(intel); 23103b705cfSriastradh intel_end_vertex(intel); 23203b705cfSriastradh 23303b705cfSriastradh if (intel->batch_flush) 23403b705cfSriastradh intel->batch_flush(intel); 23503b705cfSriastradh 23603b705cfSriastradh if (intel->batch_used == 0) 23703b705cfSriastradh return; 23803b705cfSriastradh 23903b705cfSriastradh /* Mark the end of the batchbuffer. */ 24003b705cfSriastradh OUT_BATCH(MI_BATCH_BUFFER_END); 24103b705cfSriastradh /* Emit a padding dword if we aren't going to be quad-word aligned. */ 24203b705cfSriastradh if (intel->batch_used & 1) 24303b705cfSriastradh OUT_BATCH(MI_NOOP); 24403b705cfSriastradh 24503b705cfSriastradh if (DUMP_BATCHBUFFERS) { 24603b705cfSriastradh FILE *file = fopen(DUMP_BATCHBUFFERS, "a"); 24703b705cfSriastradh if (file) { 24803b705cfSriastradh fwrite (intel->batch_ptr, intel->batch_used*4, 1, file); 24903b705cfSriastradh fclose(file); 25003b705cfSriastradh } 25103b705cfSriastradh } 25203b705cfSriastradh 25303b705cfSriastradh ret = dri_bo_subdata(intel->batch_bo, 0, intel->batch_used*4, intel->batch_ptr); 25403b705cfSriastradh if (ret == 0) { 25503b705cfSriastradh ret = drm_intel_bo_mrb_exec(intel->batch_bo, 25603b705cfSriastradh intel->batch_used*4, 25703b705cfSriastradh NULL, 0, 0xffffffff, 25803b705cfSriastradh (HAS_BLT(intel) ? 25903b705cfSriastradh intel->current_batch: 26003b705cfSriastradh I915_EXEC_DEFAULT)); 26103b705cfSriastradh } 26203b705cfSriastradh 26303b705cfSriastradh if (ret != 0) { 26403b705cfSriastradh static int once; 26503b705cfSriastradh if (!once) { 26603b705cfSriastradh if (ret == -EIO) { 26703b705cfSriastradh /* The GPU has hung and unlikely to recover by this point. */ 26803b705cfSriastradh xf86DrvMsg(scrn->scrnIndex, X_ERROR, "Detected a hung GPU, disabling acceleration.\n"); 26903b705cfSriastradh xf86DrvMsg(scrn->scrnIndex, X_ERROR, "When reporting this, please include i915_error_state from debugfs and the full dmesg.\n"); 27003b705cfSriastradh } else { 27103b705cfSriastradh /* The driver is broken. */ 27203b705cfSriastradh xf86DrvMsg(scrn->scrnIndex, X_ERROR, 27303b705cfSriastradh "Failed to submit batch buffer, expect rendering corruption: %s.\n ", 27403b705cfSriastradh strerror(-ret)); 27503b705cfSriastradh } 27603b705cfSriastradh uxa_set_force_fallback(xf86ScrnToScreen(scrn), TRUE); 27703b705cfSriastradh intel->force_fallback = TRUE; 27803b705cfSriastradh once = 1; 27903b705cfSriastradh } 28003b705cfSriastradh } 28103b705cfSriastradh 28203b705cfSriastradh while (!list_is_empty(&intel->batch_pixmaps)) { 28303b705cfSriastradh struct intel_pixmap *entry; 28403b705cfSriastradh 28503b705cfSriastradh entry = list_first_entry(&intel->batch_pixmaps, 28603b705cfSriastradh struct intel_pixmap, 28703b705cfSriastradh batch); 28803b705cfSriastradh 28903b705cfSriastradh entry->busy = -1; 29003b705cfSriastradh entry->dirty = 0; 29103b705cfSriastradh list_del(&entry->batch); 29203b705cfSriastradh } 29303b705cfSriastradh 29403b705cfSriastradh if (intel->debug_flush & DEBUG_FLUSH_WAIT) 29503b705cfSriastradh drm_intel_bo_wait_rendering(intel->batch_bo); 29603b705cfSriastradh 29703b705cfSriastradh intel_next_batch(scrn, intel->current_batch == I915_EXEC_BLT); 29803b705cfSriastradh 29903b705cfSriastradh if (intel->batch_commit_notify) 30003b705cfSriastradh intel->batch_commit_notify(intel); 30103b705cfSriastradh 30203b705cfSriastradh intel->current_batch = 0; 30303b705cfSriastradh} 30403b705cfSriastradh 30503b705cfSriastradhvoid intel_debug_flush(ScrnInfoPtr scrn) 30603b705cfSriastradh{ 30703b705cfSriastradh intel_screen_private *intel = intel_get_screen_private(scrn); 30803b705cfSriastradh 30903b705cfSriastradh if (intel->debug_flush & DEBUG_FLUSH_CACHES) 31003b705cfSriastradh intel_batch_emit_flush(scrn); 31103b705cfSriastradh 31203b705cfSriastradh if (intel->debug_flush & DEBUG_FLUSH_BATCHES) 31303b705cfSriastradh intel_batch_submit(scrn); 31403b705cfSriastradh} 315