| /* |
| * Copyright 2000-2001 VA Linux Systems, Inc. |
| * All Rights Reserved. |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining a |
| * copy of this software and associated documentation files (the "Software"), |
| * to deal in the Software without restriction, including without limitation |
| * on the rights to use, copy, modify, merge, publish, distribute, sub |
| * license, and/or sell copies of the Software, and to permit persons to whom |
| * the Software is furnished to do so, subject to the following conditions: |
| * |
| * The above copyright notice and this permission notice (including the next |
| * paragraph) shall be included in all copies or substantial portions of the |
| * Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL |
| * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR |
| * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
| * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
| * OTHER DEALINGS IN THE SOFTWARE. |
| */ |
| |
| /** |
| * \file mgaioctl.c |
| * MGA IOCTL related wrapper functions. |
| * |
| * \author Keith Whitwell <keith@tungstengraphics.com> |
| * \author Gareth Hughes <gareth@valinux.com> |
| */ |
| |
| #include <errno.h> |
| #include "mtypes.h" |
| #include "macros.h" |
| #include "dd.h" |
| #include "swrast/swrast.h" |
| |
| #include "mm.h" |
| #include "drm.h" |
| #include "mga_drm.h" |
| #include "mgacontext.h" |
| #include "mgadd.h" |
| #include "mgastate.h" |
| #include "mgatex.h" |
| #include "mgavb.h" |
| #include "mgaioctl.h" |
| #include "mgatris.h" |
| |
| #include "vblank.h" |
| |
| |
| static int |
| mgaSetFence( mgaContextPtr mmesa, uint32_t * fence ) |
| { |
| int ret = ENOSYS; |
| |
| if ( mmesa->driScreen->drm_version.minor >= 2 ) { |
| ret = drmCommandWriteRead( mmesa->driScreen->fd, DRM_MGA_SET_FENCE, |
| fence, sizeof( uint32_t )); |
| if (ret) { |
| fprintf(stderr, "drmMgaSetFence: %d\n", ret); |
| exit(1); |
| } |
| } |
| |
| return ret; |
| } |
| |
| |
| static int |
| mgaWaitFence( mgaContextPtr mmesa, uint32_t fence, uint32_t * curr_fence ) |
| { |
| int ret = ENOSYS; |
| |
| if ( mmesa->driScreen->drm_version.minor >= 2 ) { |
| uint32_t temp = fence; |
| |
| ret = drmCommandWriteRead( mmesa->driScreen->fd, |
| DRM_MGA_WAIT_FENCE, |
| & temp, sizeof( uint32_t )); |
| if (ret) { |
| fprintf(stderr, "drmMgaSetFence: %d\n", ret); |
| exit(1); |
| } |
| |
| if ( curr_fence ) { |
| *curr_fence = temp; |
| } |
| } |
| |
| return ret; |
| } |
| |
| |
| static void mga_iload_dma_ioctl(mgaContextPtr mmesa, |
| unsigned long dest, |
| int length) |
| { |
| drmBufPtr buf = mmesa->iload_buffer; |
| drm_mga_iload_t iload; |
| int ret, i; |
| |
| if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL) |
| fprintf(stderr, "DRM_IOCTL_MGA_ILOAD idx %d dst %x length %d\n", |
| buf->idx, (int) dest, length); |
| |
| if ( (length & MGA_ILOAD_MASK) != 0 ) { |
| UNLOCK_HARDWARE( mmesa ); |
| fprintf( stderr, "%s: Invalid ILOAD datasize (%d), must be " |
| "multiple of %u.\n", __FUNCTION__, length, MGA_ILOAD_ALIGN ); |
| exit( 1 ); |
| } |
| |
| iload.idx = buf->idx; |
| iload.dstorg = dest; |
| iload.length = length; |
| |
| i = 0; |
| do { |
| ret = drmCommandWrite( mmesa->driFd, DRM_MGA_ILOAD, |
| &iload, sizeof(iload) ); |
| } while ( ret == -EBUSY && i++ < DRM_MGA_IDLE_RETRY ); |
| |
| if ( ret < 0 ) { |
| printf("send iload retcode = %d\n", ret); |
| exit(1); |
| } |
| |
| mmesa->iload_buffer = 0; |
| |
| if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL) |
| fprintf(stderr, "finished iload dma put\n"); |
| |
| } |
| |
| drmBufPtr mga_get_buffer_ioctl( mgaContextPtr mmesa ) |
| { |
| int idx = 0; |
| int size = 0; |
| drmDMAReq dma; |
| int retcode; |
| drmBufPtr buf; |
| |
| if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL) |
| fprintf(stderr, "Getting dma buffer\n"); |
| |
| dma.context = mmesa->hHWContext; |
| dma.send_count = 0; |
| dma.send_list = NULL; |
| dma.send_sizes = NULL; |
| dma.flags = 0; |
| dma.request_count = 1; |
| dma.request_size = MGA_BUFFER_SIZE; |
| dma.request_list = &idx; |
| dma.request_sizes = &size; |
| dma.granted_count = 0; |
| |
| |
| if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL) |
| fprintf(stderr, "drmDMA (get) ctx %d count %d size 0x%x\n", |
| dma.context, dma.request_count, |
| dma.request_size); |
| |
| while (1) { |
| retcode = drmDMA(mmesa->driFd, &dma); |
| |
| if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL) |
| fprintf(stderr, "retcode %d sz %d idx %d count %d\n", |
| retcode, |
| dma.request_sizes[0], |
| dma.request_list[0], |
| dma.granted_count); |
| |
| if (retcode == 0 && |
| dma.request_sizes[0] && |
| dma.granted_count) |
| break; |
| |
| if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL) |
| fprintf(stderr, "\n\nflush"); |
| |
| UPDATE_LOCK( mmesa, DRM_LOCK_FLUSH | DRM_LOCK_QUIESCENT ); |
| } |
| |
| buf = &(mmesa->mgaScreen->bufs->list[idx]); |
| buf->used = 0; |
| |
| if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL) |
| fprintf(stderr, |
| "drmDMA (get) returns size[0] 0x%x idx[0] %d\n" |
| "dma_buffer now: buf idx: %d size: %d used: %d addr %p\n", |
| dma.request_sizes[0], dma.request_list[0], |
| buf->idx, buf->total, |
| buf->used, buf->address); |
| |
| if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL) |
| fprintf(stderr, "finished getbuffer\n"); |
| |
| return buf; |
| } |
| |
| |
| |
| |
| static void |
| mgaClear( GLcontext *ctx, GLbitfield mask ) |
| { |
| mgaContextPtr mmesa = MGA_CONTEXT(ctx); |
| __DRIdrawablePrivate *dPriv = mmesa->driDrawable; |
| GLuint flags = 0; |
| GLuint clear_color = mmesa->ClearColor; |
| GLuint clear_depth = 0; |
| GLuint color_mask = 0; |
| GLuint depth_mask = 0; |
| int ret; |
| int i; |
| static int nrclears; |
| drm_mga_clear_t clear; |
| GLint cx, cy, cw, ch; |
| |
| FLUSH_BATCH( mmesa ); |
| |
| if ( mask & BUFFER_BIT_FRONT_LEFT ) { |
| flags |= MGA_FRONT; |
| color_mask = mmesa->setup.plnwt; |
| mask &= ~BUFFER_BIT_FRONT_LEFT; |
| } |
| |
| if ( mask & BUFFER_BIT_BACK_LEFT ) { |
| flags |= MGA_BACK; |
| color_mask = mmesa->setup.plnwt; |
| mask &= ~BUFFER_BIT_BACK_LEFT; |
| } |
| |
| if ( (mask & BUFFER_BIT_DEPTH) && ctx->Depth.Mask ) { |
| flags |= MGA_DEPTH; |
| clear_depth = (mmesa->ClearDepth & mmesa->depth_clear_mask); |
| depth_mask |= mmesa->depth_clear_mask; |
| mask &= ~BUFFER_BIT_DEPTH; |
| } |
| |
| if ( (mask & BUFFER_BIT_STENCIL) && mmesa->hw_stencil ) { |
| flags |= MGA_DEPTH; |
| clear_depth |= (ctx->Stencil.Clear & mmesa->stencil_clear_mask); |
| depth_mask |= mmesa->stencil_clear_mask; |
| mask &= ~BUFFER_BIT_STENCIL; |
| } |
| |
| if ( flags ) { |
| LOCK_HARDWARE( mmesa ); |
| |
| /* compute region after locking: */ |
| cx = ctx->DrawBuffer->_Xmin; |
| cy = ctx->DrawBuffer->_Ymin; |
| cw = ctx->DrawBuffer->_Xmax - cx; |
| ch = ctx->DrawBuffer->_Ymax - cy; |
| |
| if ( mmesa->dirty_cliprects ) |
| mgaUpdateRects( mmesa, (MGA_FRONT | MGA_BACK) ); |
| |
| /* flip top to bottom */ |
| cy = dPriv->h-cy-ch; |
| cx += mmesa->drawX; |
| cy += mmesa->drawY; |
| |
| if ( MGA_DEBUG & DEBUG_VERBOSE_IOCTL ) |
| fprintf( stderr, "Clear, bufs %x nbox %d\n", |
| (int)flags, (int)mmesa->numClipRects ); |
| |
| for (i = 0 ; i < mmesa->numClipRects ; ) |
| { |
| int nr = MIN2(i + MGA_NR_SAREA_CLIPRECTS, mmesa->numClipRects); |
| drm_clip_rect_t *box = mmesa->pClipRects; |
| drm_clip_rect_t *b = mmesa->sarea->boxes; |
| int n = 0; |
| |
| if (cw != dPriv->w || ch != dPriv->h) { |
| /* clear subregion */ |
| for ( ; i < nr ; i++) { |
| GLint x = box[i].x1; |
| GLint y = box[i].y1; |
| GLint w = box[i].x2 - x; |
| GLint h = box[i].y2 - y; |
| |
| if (x < cx) w -= cx - x, x = cx; |
| if (y < cy) h -= cy - y, y = cy; |
| if (x + w > cx + cw) w = cx + cw - x; |
| if (y + h > cy + ch) h = cy + ch - y; |
| if (w <= 0) continue; |
| if (h <= 0) continue; |
| |
| b->x1 = x; |
| b->y1 = y; |
| b->x2 = x + w; |
| b->y2 = y + h; |
| b++; |
| n++; |
| } |
| } else { |
| /* clear whole window */ |
| for ( ; i < nr ; i++) { |
| *b++ = box[i]; |
| n++; |
| } |
| } |
| |
| |
| if ( MGA_DEBUG & DEBUG_VERBOSE_IOCTL ) |
| fprintf( stderr, |
| "DRM_IOCTL_MGA_CLEAR flag 0x%x color %x depth %x nbox %d\n", |
| flags, clear_color, clear_depth, mmesa->sarea->nbox ); |
| |
| mmesa->sarea->nbox = n; |
| |
| clear.flags = flags; |
| clear.clear_color = clear_color; |
| clear.clear_depth = clear_depth; |
| clear.color_mask = color_mask; |
| clear.depth_mask = depth_mask; |
| ret = drmCommandWrite( mmesa->driFd, DRM_MGA_CLEAR, |
| &clear, sizeof(clear)); |
| if ( ret ) { |
| fprintf( stderr, "send clear retcode = %d\n", ret ); |
| exit( 1 ); |
| } |
| if ( MGA_DEBUG & DEBUG_VERBOSE_IOCTL ) |
| fprintf( stderr, "finished clear %d\n", ++nrclears ); |
| } |
| |
| UNLOCK_HARDWARE( mmesa ); |
| mmesa->dirty |= MGA_UPLOAD_CLIPRECTS|MGA_UPLOAD_CONTEXT; |
| } |
| |
| if (mask) |
| _swrast_Clear( ctx, mask ); |
| } |
| |
| |
| /** |
| * Wait for the previous frame of rendering has completed. |
| * |
| * \param mmesa Hardware context pointer. |
| * |
| * \bug |
| * The loop in this function should have some sort of a timeout mechanism. |
| * |
| * \warning |
| * This routine used to assume that the hardware lock was held on entry. It |
| * now assumes that the lock is \b not held on entry. |
| */ |
| |
| static void mgaWaitForFrameCompletion( mgaContextPtr mmesa ) |
| { |
| if ( mgaWaitFence( mmesa, mmesa->last_frame_fence, NULL ) == ENOSYS ) { |
| unsigned wait = 0; |
| GLuint last_frame; |
| GLuint last_wrap; |
| |
| |
| LOCK_HARDWARE( mmesa ); |
| last_frame = mmesa->sarea->last_frame.head; |
| last_wrap = mmesa->sarea->last_frame.wrap; |
| |
| /* The DMA routines in the kernel track a couple values in the SAREA |
| * that we use here. The number of times that the primary DMA buffer |
| * has "wrapped" around is tracked in last_wrap. In addition, the |
| * wrap count and the buffer position at the end of the last frame are |
| * stored in last_frame.wrap and last_frame.head. |
| * |
| * By comparing the wrap counts and the current DMA pointer value |
| * (read directly from the hardware) to last_frame.head, we can |
| * determine when the graphics processor has processed all of the |
| * commands for the last frame. |
| * |
| * In this case "last frame" means the frame of the *previous* swap- |
| * buffers call. This is done to prevent queuing a second buffer swap |
| * before the previous swap is executed. |
| */ |
| while ( 1 ) { |
| if ( last_wrap < mmesa->sarea->last_wrap || |
| ( last_wrap == mmesa->sarea->last_wrap && |
| last_frame <= (MGA_READ( MGAREG_PRIMADDRESS ) - |
| mmesa->primary_offset) ) ) { |
| break; |
| } |
| if ( 0 ) { |
| wait++; |
| fprintf( stderr, " last: head=0x%06x wrap=%d\n", |
| last_frame, last_wrap ); |
| fprintf( stderr, " head: head=0x%06lx wrap=%d\n", |
| (long)(MGA_READ( MGAREG_PRIMADDRESS ) - mmesa->primary_offset), |
| mmesa->sarea->last_wrap ); |
| } |
| UPDATE_LOCK( mmesa, DRM_LOCK_FLUSH ); |
| |
| UNLOCK_HARDWARE( mmesa ); |
| DO_USLEEP( 1 ); |
| LOCK_HARDWARE( mmesa ); |
| } |
| if ( wait ) |
| fprintf( stderr, "\n" ); |
| |
| UNLOCK_HARDWARE( mmesa ); |
| } |
| } |
| |
| |
| /* |
| * Copy the back buffer to the front buffer. |
| */ |
| void mgaCopyBuffer( __DRIdrawablePrivate *dPriv ) |
| { |
| mgaContextPtr mmesa; |
| drm_clip_rect_t *pbox; |
| GLint nbox; |
| GLint ret; |
| GLint i; |
| GLboolean missed_target; |
| __DRIscreenPrivate *psp = dPriv->driScreenPriv; |
| |
| assert(dPriv); |
| assert(dPriv->driContextPriv); |
| assert(dPriv->driContextPriv->driverPrivate); |
| |
| mmesa = (mgaContextPtr) dPriv->driContextPriv->driverPrivate; |
| |
| FLUSH_BATCH( mmesa ); |
| |
| mgaWaitForFrameCompletion( mmesa ); |
| driWaitForVBlank( dPriv, & missed_target ); |
| if ( missed_target ) { |
| mmesa->swap_missed_count++; |
| (void) (*psp->systemTime->getUST)( & mmesa->swap_missed_ust ); |
| } |
| LOCK_HARDWARE( mmesa ); |
| |
| /* Use the frontbuffer cliprects |
| */ |
| if (mmesa->dirty_cliprects & MGA_FRONT) |
| mgaUpdateRects( mmesa, MGA_FRONT ); |
| |
| |
| pbox = dPriv->pClipRects; |
| nbox = dPriv->numClipRects; |
| |
| for (i = 0 ; i < nbox ; ) |
| { |
| int nr = MIN2(i + MGA_NR_SAREA_CLIPRECTS, dPriv->numClipRects); |
| drm_clip_rect_t *b = mmesa->sarea->boxes; |
| |
| mmesa->sarea->nbox = nr - i; |
| |
| for ( ; i < nr ; i++) |
| *b++ = pbox[i]; |
| |
| if (0) |
| fprintf(stderr, "DRM_IOCTL_MGA_SWAP\n"); |
| |
| ret = drmCommandNone( mmesa->driFd, DRM_MGA_SWAP ); |
| if ( ret ) { |
| printf("send swap retcode = %d\n", ret); |
| exit(1); |
| } |
| } |
| |
| (void) mgaSetFence( mmesa, & mmesa->last_frame_fence ); |
| UNLOCK_HARDWARE( mmesa ); |
| |
| mmesa->dirty |= MGA_UPLOAD_CLIPRECTS; |
| mmesa->swap_count++; |
| (void) (*psp->systemTime->getUST)( & mmesa->swap_ust ); |
| } |
| |
| |
| /** |
| * Implement the hardware-specific portion of \c glFinish. |
| * |
| * Flushes all pending commands to the hardware and wait for them to finish. |
| * |
| * \param ctx Context where the \c glFinish command was issued. |
| * |
| * \sa glFinish, mgaFlush, mgaFlushDMA |
| */ |
| static void mgaFinish( GLcontext *ctx ) |
| { |
| mgaContextPtr mmesa = MGA_CONTEXT(ctx); |
| uint32_t fence; |
| |
| |
| LOCK_HARDWARE( mmesa ); |
| if ( mmesa->vertex_dma_buffer != NULL ) { |
| mgaFlushVerticesLocked( mmesa ); |
| } |
| |
| if ( mgaSetFence( mmesa, & fence ) == 0 ) { |
| UNLOCK_HARDWARE( mmesa ); |
| (void) mgaWaitFence( mmesa, fence, NULL ); |
| } |
| else { |
| if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL) { |
| fprintf(stderr, "mgaRegetLockQuiescent\n"); |
| } |
| |
| UPDATE_LOCK( mmesa, DRM_LOCK_QUIESCENT | DRM_LOCK_FLUSH ); |
| UNLOCK_HARDWARE( mmesa ); |
| } |
| } |
| |
| |
| /** |
| * Flush all commands upto at least a certain point to the hardware. |
| * |
| * \note |
| * The term "wait" in the name of this function is misleading. It doesn't |
| * actually wait for anything. It just makes sure that the commands have |
| * been flushed to the hardware. |
| * |
| * \warning |
| * As the name implies, this function assumes that the hardware lock is |
| * held on entry. |
| */ |
| void mgaWaitAgeLocked( mgaContextPtr mmesa, int age ) |
| { |
| if (GET_DISPATCH_AGE(mmesa) < age) { |
| UPDATE_LOCK( mmesa, DRM_LOCK_FLUSH ); |
| } |
| } |
| |
| |
| static GLboolean intersect_rect( drm_clip_rect_t *out, |
| const drm_clip_rect_t *a, |
| const drm_clip_rect_t *b ) |
| { |
| *out = *a; |
| if (b->x1 > out->x1) out->x1 = b->x1; |
| if (b->y1 > out->y1) out->y1 = b->y1; |
| if (b->x2 < out->x2) out->x2 = b->x2; |
| if (b->y2 < out->y2) out->y2 = b->y2; |
| |
| return ((out->x1 < out->x2) && (out->y1 < out->y2)); |
| } |
| |
| |
| |
| |
| static void age_mmesa( mgaContextPtr mmesa, int age ) |
| { |
| if (mmesa->CurrentTexObj[0]) mmesa->CurrentTexObj[0]->age = age; |
| if (mmesa->CurrentTexObj[1]) mmesa->CurrentTexObj[1]->age = age; |
| } |
| |
| |
| void mgaFlushVerticesLocked( mgaContextPtr mmesa ) |
| { |
| drm_clip_rect_t *pbox = mmesa->pClipRects; |
| int nbox = mmesa->numClipRects; |
| drmBufPtr buffer = mmesa->vertex_dma_buffer; |
| drm_mga_vertex_t vertex; |
| int i; |
| |
| mmesa->vertex_dma_buffer = 0; |
| |
| if (!buffer) |
| return; |
| |
| if (mmesa->dirty_cliprects & mmesa->draw_buffer) |
| mgaUpdateRects( mmesa, mmesa->draw_buffer ); |
| |
| if (mmesa->dirty & ~MGA_UPLOAD_CLIPRECTS) |
| mgaEmitHwStateLocked( mmesa ); |
| |
| /* FIXME: Workaround bug in kernel module. |
| */ |
| mmesa->sarea->dirty |= MGA_UPLOAD_CONTEXT; |
| |
| if (!nbox) |
| buffer->used = 0; |
| |
| if (nbox >= MGA_NR_SAREA_CLIPRECTS) |
| mmesa->dirty |= MGA_UPLOAD_CLIPRECTS; |
| |
| #if 0 |
| if (!buffer->used || !(mmesa->dirty & MGA_UPLOAD_CLIPRECTS)) |
| { |
| if (nbox == 1) |
| mmesa->sarea->nbox = 0; |
| else |
| mmesa->sarea->nbox = nbox; |
| |
| if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL) |
| fprintf(stderr, "Firing vertex -- case a nbox %d\n", nbox); |
| |
| vertex.idx = buffer->idx; |
| vertex.used = buffer->used; |
| vertex.discard = 1; |
| drmCommandWrite( mmesa->driFd, DRM_MGA_VERTEX, |
| &vertex, sizeof(drmMGAVertex) ); |
| |
| age_mmesa(mmesa, mmesa->sarea->last_enqueue); |
| } |
| else |
| #endif |
| { |
| for (i = 0 ; i < nbox ; ) |
| { |
| int nr = MIN2(i + MGA_NR_SAREA_CLIPRECTS, nbox); |
| drm_clip_rect_t *b = mmesa->sarea->boxes; |
| int discard = 0; |
| |
| if (mmesa->scissor) { |
| mmesa->sarea->nbox = 0; |
| |
| for ( ; i < nr ; i++) { |
| *b = pbox[i]; |
| if (intersect_rect(b, b, &mmesa->scissor_rect)) { |
| mmesa->sarea->nbox++; |
| b++; |
| } |
| } |
| |
| /* Culled? |
| */ |
| if (!mmesa->sarea->nbox) { |
| if (nr < nbox) continue; |
| buffer->used = 0; |
| } |
| } else { |
| mmesa->sarea->nbox = nr - i; |
| for ( ; i < nr ; i++) |
| *b++ = pbox[i]; |
| } |
| |
| /* Finished with the buffer? |
| */ |
| if (nr == nbox) |
| discard = 1; |
| |
| mmesa->sarea->dirty |= MGA_UPLOAD_CLIPRECTS; |
| |
| vertex.idx = buffer->idx; |
| vertex.used = buffer->used; |
| vertex.discard = discard; |
| drmCommandWrite( mmesa->driFd, DRM_MGA_VERTEX, |
| &vertex, sizeof(vertex) ); |
| |
| age_mmesa(mmesa, mmesa->sarea->last_enqueue); |
| } |
| } |
| |
| mmesa->dirty &= ~MGA_UPLOAD_CLIPRECTS; |
| } |
| |
| void mgaFlushVertices( mgaContextPtr mmesa ) |
| { |
| LOCK_HARDWARE( mmesa ); |
| mgaFlushVerticesLocked( mmesa ); |
| UNLOCK_HARDWARE( mmesa ); |
| } |
| |
| |
| void mgaFireILoadLocked( mgaContextPtr mmesa, |
| GLuint offset, GLuint length ) |
| { |
| if (!mmesa->iload_buffer) { |
| fprintf(stderr, "mgaFireILoad: no buffer\n"); |
| return; |
| } |
| |
| if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL) |
| fprintf(stderr, "mgaFireILoad idx %d ofs 0x%x length %d\n", |
| mmesa->iload_buffer->idx, (int)offset, (int)length ); |
| |
| mga_iload_dma_ioctl( mmesa, offset, length ); |
| } |
| |
| void mgaGetILoadBufferLocked( mgaContextPtr mmesa ) |
| { |
| if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL) |
| fprintf(stderr, "mgaGetIloadBuffer (buffer now %p)\n", |
| (void *) mmesa->iload_buffer); |
| |
| mmesa->iload_buffer = mga_get_buffer_ioctl( mmesa ); |
| } |
| |
| |
| /** |
| * Implement the hardware-specific portion of \c glFlush. |
| * |
| * \param ctx Context to be flushed. |
| * |
| * \sa glFlush, mgaFinish, mgaFlushDMA |
| */ |
| static void mgaFlush( GLcontext *ctx ) |
| { |
| mgaContextPtr mmesa = MGA_CONTEXT( ctx ); |
| |
| |
| LOCK_HARDWARE( mmesa ); |
| if ( mmesa->vertex_dma_buffer != NULL ) { |
| mgaFlushVerticesLocked( mmesa ); |
| } |
| |
| UPDATE_LOCK( mmesa, DRM_LOCK_FLUSH ); |
| UNLOCK_HARDWARE( mmesa ); |
| } |
| |
| |
| int mgaFlushDMA( int fd, drmLockFlags flags ) |
| { |
| drm_lock_t lock; |
| int ret, i = 0; |
| |
| memset( &lock, 0, sizeof(lock) ); |
| |
| lock.flags = flags & (DRM_LOCK_QUIESCENT | DRM_LOCK_FLUSH |
| | DRM_LOCK_FLUSH_ALL); |
| |
| do { |
| ret = drmCommandWrite( fd, DRM_MGA_FLUSH, &lock, sizeof(lock) ); |
| } while ( ret && errno == EBUSY && i++ < DRM_MGA_IDLE_RETRY ); |
| |
| if ( ret == 0 ) |
| return 0; |
| if ( errno != EBUSY ) |
| return -errno; |
| |
| if ( lock.flags & DRM_LOCK_QUIESCENT ) { |
| /* Only keep trying if we need quiescence. |
| */ |
| lock.flags &= ~(DRM_LOCK_FLUSH | DRM_LOCK_FLUSH_ALL); |
| |
| do { |
| ret = drmCommandWrite( fd, DRM_MGA_FLUSH, &lock, sizeof(lock) ); |
| } while ( ret && errno == EBUSY && i++ < DRM_MGA_IDLE_RETRY ); |
| } |
| |
| if ( ret == 0 ) { |
| return 0; |
| } else { |
| return -errno; |
| } |
| } |
| |
| void mgaInitIoctlFuncs( struct dd_function_table *functions ) |
| { |
| functions->Clear = mgaClear; |
| functions->Flush = mgaFlush; |
| functions->Finish = mgaFinish; |
| } |