1fa225cbcSrjs/* -*- c-basic-offset: 4 -*- */ 2fa225cbcSrjs/* 3fa225cbcSrjs * Copyright © 2006 Intel Corporation 4fa225cbcSrjs * 5fa225cbcSrjs * Permission is hereby granted, free of charge, to any person obtaining a 6fa225cbcSrjs * copy of this software and associated documentation files (the "Software"), 7fa225cbcSrjs * to deal in the Software without restriction, including without limitation 8fa225cbcSrjs * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9fa225cbcSrjs * and/or sell copies of the Software, and to permit persons to whom the 10fa225cbcSrjs * Software is furnished to do so, subject to the following conditions: 11fa225cbcSrjs * 12fa225cbcSrjs * The above copyright notice and this permission notice (including the next 13fa225cbcSrjs * paragraph) shall be included in all copies or substantial portions of the 14fa225cbcSrjs * Software. 15fa225cbcSrjs * 16fa225cbcSrjs * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17fa225cbcSrjs * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18fa225cbcSrjs * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19fa225cbcSrjs * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20fa225cbcSrjs * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21fa225cbcSrjs * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22fa225cbcSrjs * SOFTWARE. 23fa225cbcSrjs * 24fa225cbcSrjs * Authors: 25fa225cbcSrjs * Eric Anholt <eric@anholt.net> 26fa225cbcSrjs * 27fa225cbcSrjs */ 28fa225cbcSrjs 29fa225cbcSrjs#ifdef HAVE_CONFIG_H 30fa225cbcSrjs#include "config.h" 31fa225cbcSrjs#endif 32fa225cbcSrjs 33fa225cbcSrjs#include <assert.h> 34fa225cbcSrjs#include <stdlib.h> 35fa225cbcSrjs#include <errno.h> 36fa225cbcSrjs 37fa225cbcSrjs#include "xf86.h" 38fa225cbcSrjs#include "i830.h" 39fa225cbcSrjs#include "i830_ring.h" 40fa225cbcSrjs#include "i915_drm.h" 41fa225cbcSrjs 42fa225cbcSrjsstatic int 43fa225cbcSrjsintel_nondrm_exec(dri_bo *bo, unsigned int used, void *priv) 44fa225cbcSrjs{ 45fa225cbcSrjs ScrnInfoPtr pScrn = priv; 46fa225cbcSrjs I830Ptr pI830 = I830PTR(pScrn); 47fa225cbcSrjs 48fa225cbcSrjs BEGIN_LP_RING(4); 49fa225cbcSrjs OUT_RING(MI_BATCH_BUFFER_START | (2 << 6)); 50fa225cbcSrjs OUT_RING(bo->offset); 51fa225cbcSrjs OUT_RING(MI_NOOP); 52fa225cbcSrjs OUT_RING(MI_NOOP); 53fa225cbcSrjs ADVANCE_LP_RING(); 54fa225cbcSrjs 55fa225cbcSrjs return 0; 56fa225cbcSrjs} 57fa225cbcSrjs 58fa225cbcSrjsstatic int 59fa225cbcSrjsintel_nondrm_exec_i830(dri_bo *bo, unsigned int used, void *priv) 60fa225cbcSrjs{ 61fa225cbcSrjs ScrnInfoPtr pScrn = priv; 62fa225cbcSrjs I830Ptr pI830 = I830PTR(pScrn); 63fa225cbcSrjs 64fa225cbcSrjs BEGIN_LP_RING(4); 65fa225cbcSrjs OUT_RING(MI_BATCH_BUFFER); 66fa225cbcSrjs OUT_RING(bo->offset); 67fa225cbcSrjs OUT_RING(bo->offset + pI830->batch_used - 4); 68fa225cbcSrjs OUT_RING(MI_NOOP); 69fa225cbcSrjs ADVANCE_LP_RING(); 70fa225cbcSrjs 71fa225cbcSrjs return 0; 72fa225cbcSrjs} 73fa225cbcSrjs 74fa225cbcSrjs/** 75fa225cbcSrjs * Creates a fence value representing a request to be passed. 76fa225cbcSrjs * 77fa225cbcSrjs * Stub implementation that should be avoided when DRM functions are available. 78fa225cbcSrjs */ 79fa225cbcSrjsstatic unsigned int 80fa225cbcSrjsintel_nondrm_emit(void *priv) 81fa225cbcSrjs{ 82fa225cbcSrjs static unsigned int fence = 0; 83fa225cbcSrjs 84fa225cbcSrjs /* Match DRM in not using half the range. The fake bufmgr relies on this. */ 85fa225cbcSrjs if (++fence >= 0x8000000) 86fa225cbcSrjs fence = 1; 87fa225cbcSrjs 88fa225cbcSrjs return fence; 89fa225cbcSrjs} 90fa225cbcSrjs 91fa225cbcSrjs/** 92fa225cbcSrjs * Waits on a fence representing a request to be passed. 93fa225cbcSrjs * 94fa225cbcSrjs * Stub implementation that should be avoided when DRM functions are available. 95fa225cbcSrjs */ 96fa225cbcSrjsstatic void 97fa225cbcSrjsintel_nondrm_wait(unsigned int fence, void *priv) 98fa225cbcSrjs{ 99fa225cbcSrjs ScrnInfoPtr pScrn = priv; 100fa225cbcSrjs 101fa225cbcSrjs i830_wait_ring_idle(pScrn); 102fa225cbcSrjs} 103fa225cbcSrjs 104fa225cbcSrjsstatic void 105fa225cbcSrjsintel_next_batch(ScrnInfoPtr pScrn) 106fa225cbcSrjs{ 107fa225cbcSrjs I830Ptr pI830 = I830PTR(pScrn); 108fa225cbcSrjs 109fa225cbcSrjs /* The 865 has issues with larger-than-page-sized batch buffers. */ 110fa225cbcSrjs if (IS_I865G(pI830)) 111fa225cbcSrjs pI830->batch_bo = dri_bo_alloc(pI830->bufmgr, "batch", 4096, 4096); 112fa225cbcSrjs else 113fa225cbcSrjs pI830->batch_bo = dri_bo_alloc(pI830->bufmgr, "batch", 4096 * 4, 4096); 114fa225cbcSrjs 115fa225cbcSrjs if (dri_bo_map(pI830->batch_bo, 1) != 0) 116fa225cbcSrjs FatalError("Failed to map batchbuffer: %s\n", strerror(errno)); 117fa225cbcSrjs 118fa225cbcSrjs pI830->batch_used = 0; 119fa225cbcSrjs pI830->batch_ptr = pI830->batch_bo->virtual; 120fa225cbcSrjs 121fa225cbcSrjs /* If we are using DRI2, we don't know when another client has executed, 122fa225cbcSrjs * so we have to reinitialize our 3D state per batch. 123fa225cbcSrjs */ 124fa225cbcSrjs if (pI830->directRenderingType == DRI_DRI2) 125fa225cbcSrjs pI830->last_3d = LAST_3D_OTHER; 126fa225cbcSrjs} 127fa225cbcSrjs 128fa225cbcSrjsvoid 129fa225cbcSrjsintel_batch_init(ScrnInfoPtr pScrn) 130fa225cbcSrjs{ 131fa225cbcSrjs I830Ptr pI830 = I830PTR(pScrn); 132fa225cbcSrjs 133fa225cbcSrjs pI830->batch_emit_start = 0; 134fa225cbcSrjs pI830->batch_emitting = 0; 135fa225cbcSrjs 136fa225cbcSrjs intel_next_batch(pScrn); 137fa225cbcSrjs 138fa225cbcSrjs if (!pI830->have_gem) { 139fa225cbcSrjs if (IS_I830(pI830) || IS_845G(pI830)) { 140fa225cbcSrjs intel_bufmgr_fake_set_exec_callback(pI830->bufmgr, 141fa225cbcSrjs intel_nondrm_exec_i830, 142fa225cbcSrjs pScrn); 143fa225cbcSrjs } else { 144fa225cbcSrjs intel_bufmgr_fake_set_exec_callback(pI830->bufmgr, 145fa225cbcSrjs intel_nondrm_exec, 146fa225cbcSrjs pScrn); 147fa225cbcSrjs } 148fa225cbcSrjs intel_bufmgr_fake_set_fence_callback(pI830->bufmgr, 149fa225cbcSrjs intel_nondrm_emit, 150fa225cbcSrjs intel_nondrm_wait, 151fa225cbcSrjs pScrn); 152fa225cbcSrjs } 153fa225cbcSrjs} 154fa225cbcSrjs 155fa225cbcSrjsvoid 156fa225cbcSrjsintel_batch_teardown(ScrnInfoPtr pScrn) 157fa225cbcSrjs{ 158fa225cbcSrjs I830Ptr pI830 = I830PTR(pScrn); 159fa225cbcSrjs 160fa225cbcSrjs if (pI830->batch_ptr != NULL) { 161fa225cbcSrjs dri_bo_unmap(pI830->batch_bo); 162fa225cbcSrjs pI830->batch_ptr = NULL; 163fa225cbcSrjs 164fa225cbcSrjs dri_bo_unreference(pI830->batch_bo); 165fa225cbcSrjs pI830->batch_bo = NULL; 166fa225cbcSrjs 167fa225cbcSrjs dri_bo_unreference(pI830->last_batch_bo); 168fa225cbcSrjs pI830->last_batch_bo = NULL; 169fa225cbcSrjs } 170fa225cbcSrjs} 171fa225cbcSrjs 172fa225cbcSrjsvoid 173fa225cbcSrjsintel_batch_flush(ScrnInfoPtr pScrn, Bool flushed) 174fa225cbcSrjs{ 175fa225cbcSrjs I830Ptr pI830 = I830PTR(pScrn); 176fa225cbcSrjs int ret; 177fa225cbcSrjs 178fa225cbcSrjs if (pI830->batch_used == 0) 179fa225cbcSrjs return; 180fa225cbcSrjs 181fa225cbcSrjs /* If we're not using GEM, then emit a flush after each batch buffer */ 182fa225cbcSrjs if (!pI830->have_gem && !flushed) { 183fa225cbcSrjs int flags = MI_WRITE_DIRTY_STATE | MI_INVALIDATE_MAP_CACHE; 184fa225cbcSrjs 185fa225cbcSrjs if (IS_I965G(pI830)) 186fa225cbcSrjs flags = 0; 187fa225cbcSrjs 188fa225cbcSrjs *(uint32_t *)(pI830->batch_ptr + pI830->batch_used) = MI_FLUSH | flags; 189fa225cbcSrjs pI830->batch_used += 4; 190fa225cbcSrjs } 191fa225cbcSrjs 192fa225cbcSrjs /* Emit a padding dword if we aren't going to be quad-word aligned. */ 193fa225cbcSrjs if ((pI830->batch_used & 4) == 0) { 194fa225cbcSrjs *(uint32_t *)(pI830->batch_ptr + pI830->batch_used) = MI_NOOP; 195fa225cbcSrjs pI830->batch_used += 4; 196fa225cbcSrjs } 197fa225cbcSrjs 198fa225cbcSrjs /* Mark the end of the batchbuffer. */ 199fa225cbcSrjs *(uint32_t *)(pI830->batch_ptr + pI830->batch_used) = MI_BATCH_BUFFER_END; 200fa225cbcSrjs pI830->batch_used += 4; 201fa225cbcSrjs 202fa225cbcSrjs dri_bo_unmap(pI830->batch_bo); 203fa225cbcSrjs pI830->batch_ptr = NULL; 204fa225cbcSrjs 205fa225cbcSrjs ret = dri_bo_exec(pI830->batch_bo, pI830->batch_used, NULL, 0, 0xffffffff); 206fa225cbcSrjs if (ret != 0) 207fa225cbcSrjs FatalError("Failed to submit batchbuffer: %s\n", strerror(-ret)); 208fa225cbcSrjs 209fa225cbcSrjs /* Save a ref to the last batch emitted, which we use for syncing 210fa225cbcSrjs * in debug code. 211fa225cbcSrjs */ 212fa225cbcSrjs dri_bo_unreference(pI830->last_batch_bo); 213fa225cbcSrjs pI830->last_batch_bo = pI830->batch_bo; 214fa225cbcSrjs pI830->batch_bo = NULL; 215fa225cbcSrjs 216fa225cbcSrjs intel_next_batch(pScrn); 217fa225cbcSrjs 218fa225cbcSrjs /* Mark that we need to flush whatever potential rendering we've done in the 219fa225cbcSrjs * blockhandler. We could set this less often, but it's probably not worth 220fa225cbcSrjs * the work. 221fa225cbcSrjs */ 222fa225cbcSrjs if (pI830->have_gem) 223fa225cbcSrjs pI830->need_mi_flush = TRUE; 224fa225cbcSrjs 225fa225cbcSrjs if (pI830->batch_flush_notify) 226fa225cbcSrjs pI830->batch_flush_notify (pScrn); 227fa225cbcSrjs} 228fa225cbcSrjs 229fa225cbcSrjs/** Waits on the last emitted batchbuffer to be completed. */ 230fa225cbcSrjsvoid 231fa225cbcSrjsintel_batch_wait_last(ScrnInfoPtr scrn) 232fa225cbcSrjs{ 233fa225cbcSrjs I830Ptr pI830 = I830PTR(scrn); 234fa225cbcSrjs 235fa225cbcSrjs /* Map it CPU write, which guarantees it's done. This is a completely 236fa225cbcSrjs * non performance path, so we don't need anything better. 237fa225cbcSrjs */ 238fa225cbcSrjs drm_intel_bo_map(pI830->last_batch_bo, TRUE); 239fa225cbcSrjs drm_intel_bo_unmap(pI830->last_batch_bo); 240fa225cbcSrjs} 241fa225cbcSrjs 242