| /* $XFree86$ */ /* -*- mode: c; c-basic-offset: 3 -*- */ |
| /* |
| * Copyright 2000 Gareth Hughes |
| * 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 |
| * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| * 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 NONINFRINGEMENT. IN NO EVENT SHALL |
| * GARETH HUGHES 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. |
| */ |
| |
| /* |
| * Authors: |
| * Gareth Hughes <gareth@valinux.com> |
| * Leif Delgass <ldelgass@retinalburn.net> |
| * Jos�Fonseca <j_r_fonseca@yahoo.co.uk> |
| */ |
| #include <errno.h> |
| |
| #include "mach64_context.h" |
| #include "mach64_state.h" |
| #include "mach64_ioctl.h" |
| #include "mach64_tex.h" |
| |
| #include "imports.h" |
| #include "macros.h" |
| |
| #include "swrast/swrast.h" |
| |
| #include "vblank.h" |
| |
| #define MACH64_TIMEOUT 10 /* the DRM already has a timeout, so keep this small */ |
| |
| |
| /* ============================================================= |
| * Hardware vertex buffer handling |
| */ |
| |
| /* Get a new VB from the pool of vertex buffers in AGP space. |
| */ |
| drmBufPtr mach64GetBufferLocked( mach64ContextPtr mmesa ) |
| { |
| int fd = mmesa->mach64Screen->driScreen->fd; |
| int index = 0; |
| int size = 0; |
| drmDMAReq dma; |
| drmBufPtr buf = NULL; |
| int to = 0; |
| int ret; |
| |
| 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 = MACH64_BUFFER_SIZE; |
| dma.request_list = &index; |
| dma.request_sizes = &size; |
| dma.granted_count = 0; |
| |
| while ( !buf && ( to++ < MACH64_TIMEOUT ) ) { |
| ret = drmDMA( fd, &dma ); |
| |
| if ( ret == 0 ) { |
| buf = &mmesa->mach64Screen->buffers->list[index]; |
| buf->used = 0; |
| #if ENABLE_PERF_BOXES |
| /* Bump the performance counter */ |
| mmesa->c_vertexBuffers++; |
| #endif |
| return buf; |
| } |
| } |
| |
| if ( !buf ) { |
| drmCommandNone( fd, DRM_MACH64_RESET ); |
| UNLOCK_HARDWARE( mmesa ); |
| fprintf( stderr, "Error: Could not get new VB... exiting\n" ); |
| exit( -1 ); |
| } |
| |
| return buf; |
| } |
| |
| void mach64FlushVerticesLocked( mach64ContextPtr mmesa ) |
| { |
| drm_clip_rect_t *pbox = mmesa->pClipRects; |
| int nbox = mmesa->numClipRects; |
| void *buffer = mmesa->vert_buf; |
| int count = mmesa->vert_used; |
| int prim = mmesa->hw_primitive; |
| int fd = mmesa->driScreen->fd; |
| drm_mach64_vertex_t vertex; |
| int i; |
| |
| mmesa->num_verts = 0; |
| mmesa->vert_used = 0; |
| |
| if ( !count ) |
| return; |
| |
| if ( mmesa->dirty & ~MACH64_UPLOAD_CLIPRECTS ) |
| mach64EmitHwStateLocked( mmesa ); |
| |
| if ( !nbox ) |
| count = 0; |
| |
| if ( nbox > MACH64_NR_SAREA_CLIPRECTS ) |
| mmesa->dirty |= MACH64_UPLOAD_CLIPRECTS; |
| |
| if ( !count || !(mmesa->dirty & MACH64_UPLOAD_CLIPRECTS) ) { |
| int to = 0; |
| int ret; |
| |
| /* FIXME: Is this really necessary */ |
| if ( nbox == 1 ) |
| mmesa->sarea->nbox = 0; |
| else |
| mmesa->sarea->nbox = nbox; |
| |
| vertex.prim = prim; |
| vertex.buf = buffer; |
| vertex.used = count; |
| vertex.discard = 1; |
| do { |
| ret = drmCommandWrite( fd, DRM_MACH64_VERTEX, |
| &vertex, sizeof(drm_mach64_vertex_t) ); |
| } while ( ( ret == -EAGAIN ) && ( to++ < MACH64_TIMEOUT ) ); |
| if ( ret ) { |
| UNLOCK_HARDWARE( mmesa ); |
| fprintf( stderr, "Error flushing vertex buffer: return = %d\n", ret ); |
| exit( -1 ); |
| } |
| |
| } else { |
| |
| for ( i = 0 ; i < nbox ; ) { |
| int nr = MIN2( i + MACH64_NR_SAREA_CLIPRECTS, nbox ); |
| drm_clip_rect_t *b = mmesa->sarea->boxes; |
| int discard = 0; |
| int to = 0; |
| int ret; |
| |
| mmesa->sarea->nbox = nr - i; |
| for ( ; i < nr ; i++ ) { |
| *b++ = pbox[i]; |
| } |
| |
| /* Finished with the buffer? |
| */ |
| if ( nr == nbox ) { |
| discard = 1; |
| } |
| |
| mmesa->sarea->dirty |= MACH64_UPLOAD_CLIPRECTS; |
| |
| vertex.prim = prim; |
| vertex.buf = buffer; |
| vertex.used = count; |
| vertex.discard = discard; |
| do { |
| ret = drmCommandWrite( fd, DRM_MACH64_VERTEX, |
| &vertex, sizeof(drm_mach64_vertex_t) ); |
| } while ( ( ret == -EAGAIN ) && ( to++ < MACH64_TIMEOUT ) ); |
| if ( ret ) { |
| UNLOCK_HARDWARE( mmesa ); |
| fprintf( stderr, "Error flushing vertex buffer: return = %d\n", ret ); |
| exit( -1 ); |
| } |
| } |
| } |
| |
| mmesa->dirty &= ~MACH64_UPLOAD_CLIPRECTS; |
| } |
| |
| /* ================================================================ |
| * Texture uploads |
| */ |
| |
| void mach64FireBlitLocked( mach64ContextPtr mmesa, void *buffer, |
| GLint offset, GLint pitch, GLint format, |
| GLint x, GLint y, GLint width, GLint height ) |
| { |
| drm_mach64_blit_t blit; |
| int to = 0; |
| int ret; |
| |
| blit.buf = buffer; |
| blit.offset = offset; |
| blit.pitch = pitch; |
| blit.format = format; |
| blit.x = x; |
| blit.y = y; |
| blit.width = width; |
| blit.height = height; |
| |
| do { |
| ret = drmCommandWrite( mmesa->driFd, DRM_MACH64_BLIT, |
| &blit, sizeof(drm_mach64_blit_t) ); |
| } while ( ( ret == -EAGAIN ) && ( to++ < MACH64_TIMEOUT ) ); |
| |
| if ( ret ) { |
| UNLOCK_HARDWARE( mmesa ); |
| fprintf( stderr, "DRM_MACH64_BLIT: return = %d\n", ret ); |
| exit( -1 ); |
| } |
| } |
| |
| |
| /* ================================================================ |
| * SwapBuffers with client-side throttling |
| */ |
| static void delay( void ) { |
| /* Prevent an optimizing compiler from removing a spin loop */ |
| } |
| |
| /* Throttle the frame rate -- only allow MACH64_MAX_QUEUED_FRAMES |
| * pending swap buffers requests at a time. |
| * |
| * GH: We probably don't want a timeout here, as we can wait as |
| * long as we want for a frame to complete. If it never does, then |
| * the card has locked. |
| */ |
| static int mach64WaitForFrameCompletion( mach64ContextPtr mmesa ) |
| { |
| int fd = mmesa->driFd; |
| int i; |
| int wait = 0; |
| int frames; |
| |
| while ( 1 ) { |
| drm_mach64_getparam_t gp; |
| int ret; |
| |
| if ( mmesa->sarea->frames_queued < MACH64_MAX_QUEUED_FRAMES ) { |
| break; |
| } |
| |
| if (MACH64_DEBUG & DEBUG_NOWAIT) { |
| return 1; |
| } |
| |
| gp.param = MACH64_PARAM_FRAMES_QUEUED; |
| gp.value = &frames; /* also copied into sarea->frames_queued by DRM */ |
| |
| ret = drmCommandWriteRead( fd, DRM_MACH64_GETPARAM, &gp, sizeof(gp) ); |
| |
| if ( ret ) { |
| UNLOCK_HARDWARE( mmesa ); |
| fprintf( stderr, "DRM_MACH64_GETPARAM: return = %d\n", ret ); |
| exit( -1 ); |
| } |
| |
| /* Spin in place a bit so we aren't hammering the register */ |
| wait++; |
| |
| for ( i = 0 ; i < 1024 ; i++ ) { |
| delay(); |
| } |
| |
| } |
| |
| return wait; |
| } |
| |
| /* Copy the back color buffer to the front color buffer. |
| */ |
| void mach64CopyBuffer( __DRIdrawablePrivate *dPriv ) |
| { |
| mach64ContextPtr mmesa; |
| GLint nbox, i, ret; |
| drm_clip_rect_t *pbox; |
| GLboolean missed_target; |
| |
| assert(dPriv); |
| assert(dPriv->driContextPriv); |
| assert(dPriv->driContextPriv->driverPrivate); |
| |
| mmesa = (mach64ContextPtr) dPriv->driContextPriv->driverPrivate; |
| |
| if ( MACH64_DEBUG & DEBUG_VERBOSE_API ) { |
| fprintf( stderr, "\n********************************\n" ); |
| fprintf( stderr, "\n%s( %p )\n\n", |
| __FUNCTION__, mmesa->glCtx ); |
| fflush( stderr ); |
| } |
| |
| /* Flush any outstanding vertex buffers */ |
| FLUSH_BATCH( mmesa ); |
| |
| LOCK_HARDWARE( mmesa ); |
| |
| /* Throttle the frame rate -- only allow one pending swap buffers |
| * request at a time. |
| */ |
| if ( !mach64WaitForFrameCompletion( mmesa ) ) { |
| mmesa->hardwareWentIdle = 1; |
| } else { |
| mmesa->hardwareWentIdle = 0; |
| } |
| |
| #if ENABLE_PERF_BOXES |
| if ( mmesa->boxes ) { |
| mach64PerformanceBoxesLocked( mmesa ); |
| } |
| #endif |
| |
| UNLOCK_HARDWARE( mmesa ); |
| driWaitForVBlank( dPriv, &missed_target ); |
| LOCK_HARDWARE( mmesa ); |
| |
| /* use front buffer cliprects */ |
| nbox = dPriv->numClipRects; |
| pbox = dPriv->pClipRects; |
| |
| for ( i = 0 ; i < nbox ; ) { |
| GLint nr = MIN2( i + MACH64_NR_SAREA_CLIPRECTS , nbox ); |
| drm_clip_rect_t *b = mmesa->sarea->boxes; |
| GLint n = 0; |
| |
| for ( ; i < nr ; i++ ) { |
| *b++ = pbox[i]; |
| n++; |
| } |
| mmesa->sarea->nbox = n; |
| |
| ret = drmCommandNone( mmesa->driFd, DRM_MACH64_SWAP ); |
| |
| if ( ret ) { |
| UNLOCK_HARDWARE( mmesa ); |
| fprintf( stderr, "DRM_MACH64_SWAP: return = %d\n", ret ); |
| exit( -1 ); |
| } |
| } |
| |
| if ( MACH64_DEBUG & DEBUG_ALWAYS_SYNC ) { |
| mach64WaitForIdleLocked( mmesa ); |
| } |
| |
| UNLOCK_HARDWARE( mmesa ); |
| |
| mmesa->dirty |= (MACH64_UPLOAD_CONTEXT | |
| MACH64_UPLOAD_MISC | |
| MACH64_UPLOAD_CLIPRECTS); |
| |
| #if ENABLE_PERF_BOXES |
| /* Log the performance counters if necessary */ |
| mach64PerformanceCounters( mmesa ); |
| #endif |
| } |
| |
| #if ENABLE_PERF_BOXES |
| /* ================================================================ |
| * Performance monitoring |
| */ |
| |
| void mach64PerformanceCounters( mach64ContextPtr mmesa ) |
| { |
| |
| if (MACH64_DEBUG & DEBUG_VERBOSE_COUNT) { |
| /* report performance counters */ |
| fprintf( stderr, "mach64CopyBuffer: vertexBuffers:%i drawWaits:%i clears:%i\n", |
| mmesa->c_vertexBuffers, mmesa->c_drawWaits, mmesa->c_clears ); |
| } |
| |
| mmesa->c_vertexBuffers = 0; |
| mmesa->c_drawWaits = 0; |
| mmesa->c_clears = 0; |
| |
| if ( mmesa->c_textureSwaps || mmesa->c_textureBytes || mmesa->c_agpTextureBytes ) { |
| if (MACH64_DEBUG & DEBUG_VERBOSE_COUNT) { |
| fprintf( stderr, " textureSwaps:%i textureBytes:%i agpTextureBytes:%i\n", |
| mmesa->c_textureSwaps, mmesa->c_textureBytes, mmesa->c_agpTextureBytes ); |
| } |
| mmesa->c_textureSwaps = 0; |
| mmesa->c_textureBytes = 0; |
| mmesa->c_agpTextureBytes = 0; |
| } |
| |
| mmesa->c_texsrc_agp = 0; |
| mmesa->c_texsrc_card = 0; |
| |
| if (MACH64_DEBUG & DEBUG_VERBOSE_COUNT) |
| fprintf( stderr, "---------------------------------------------------------\n" ); |
| } |
| |
| |
| void mach64PerformanceBoxesLocked( mach64ContextPtr mmesa ) |
| { |
| GLint ret; |
| drm_mach64_clear_t clear; |
| GLint x, y, w, h; |
| GLuint color; |
| GLint nbox; |
| GLint x1, y1, x2, y2; |
| drm_clip_rect_t *b = mmesa->sarea->boxes; |
| |
| /* save cliprects */ |
| nbox = mmesa->sarea->nbox; |
| x1 = b[0].x1; |
| y1 = b[0].y1; |
| x2 = b[0].x2; |
| y2 = b[0].y2; |
| |
| /* setup a single cliprect and call the clear ioctl for each box */ |
| mmesa->sarea->nbox = 1; |
| |
| w = h = 8; |
| x = mmesa->drawX; |
| y = mmesa->drawY; |
| b[0].x1 = x; |
| b[0].x2 = x + w; |
| b[0].y1 = y; |
| b[0].y2 = y + h; |
| |
| clear.flags = MACH64_BACK; |
| clear.clear_depth = 0; |
| |
| /* Red box if DDFinish was called to wait for rendering to complete */ |
| if ( mmesa->c_drawWaits ) { |
| color = mach64PackColor( mmesa->mach64Screen->cpp, 255, 0, 0, 0 ); |
| |
| clear.x = x; |
| clear.y = y; |
| clear.w = w; |
| clear.h = h; |
| clear.clear_color = color; |
| |
| ret = drmCommandWrite( mmesa->driFd, DRM_MACH64_CLEAR, |
| &clear, sizeof(drm_mach64_clear_t) ); |
| |
| if (ret < 0) { |
| UNLOCK_HARDWARE( mmesa ); |
| fprintf( stderr, "DRM_MACH64_CLEAR: return = %d\n", ret ); |
| exit( -1 ); |
| } |
| |
| } |
| |
| x += w; |
| b[0].x1 = x; |
| b[0].x2 = x + w; |
| |
| /* draw a green box if we had to wait for previous frame(s) to complete */ |
| if ( !mmesa->hardwareWentIdle ) { |
| color = mach64PackColor( mmesa->mach64Screen->cpp, 0, 255, 0, 0 ); |
| |
| clear.x = x; |
| clear.y = y; |
| clear.w = w; |
| clear.h = h; |
| clear.clear_color = color; |
| |
| ret = drmCommandWrite( mmesa->driFd, DRM_MACH64_CLEAR, |
| &clear, sizeof(drm_mach64_clear_t) ); |
| |
| if (ret < 0) { |
| UNLOCK_HARDWARE( mmesa ); |
| fprintf( stderr, "DRM_MACH64_CLEAR: return = %d\n", ret ); |
| exit( -1 ); |
| } |
| |
| } |
| |
| x += w; |
| w = 20; |
| b[0].x1 = x; |
| |
| /* show approx. ratio of AGP/card textures used - Blue = AGP, Purple = Card */ |
| if ( mmesa->c_texsrc_agp || mmesa->c_texsrc_card ) { |
| color = mach64PackColor( mmesa->mach64Screen->cpp, 0, 0, 255, 0 ); |
| w = ((GLfloat)mmesa->c_texsrc_agp / (GLfloat)(mmesa->c_texsrc_agp + mmesa->c_texsrc_card))*20; |
| if (w > 1) { |
| |
| b[0].x2 = x + w; |
| |
| clear.x = x; |
| clear.y = y; |
| clear.w = w; |
| clear.h = h; |
| clear.clear_color = color; |
| |
| ret = drmCommandWrite( mmesa->driFd, DRM_MACH64_CLEAR, |
| &clear, sizeof(drm_mach64_clear_t) ); |
| |
| if (ret < 0) { |
| UNLOCK_HARDWARE( mmesa ); |
| fprintf( stderr, "DRM_MACH64_CLEAR: return = %d\n", ret ); |
| exit( -1 ); |
| } |
| } |
| |
| x += w; |
| w = 20 - w; |
| |
| if (w > 1) { |
| b[0].x1 = x; |
| b[0].x2 = x + w; |
| |
| color = mach64PackColor( mmesa->mach64Screen->cpp, 255, 0, 255, 0 ); |
| |
| clear.x = x; |
| clear.y = y; |
| clear.w = w; |
| clear.h = h; |
| clear.clear_color = color; |
| |
| ret = drmCommandWrite( mmesa->driFd, DRM_MACH64_CLEAR, |
| &clear, sizeof(drm_mach64_clear_t) ); |
| |
| if (ret < 0) { |
| UNLOCK_HARDWARE( mmesa ); |
| fprintf( stderr, "DRM_MACH64_CLEAR: return = %d\n", ret ); |
| exit( -1 ); |
| } |
| } |
| } |
| |
| x += w; |
| w = 8; |
| b[0].x1 = x; |
| b[0].x2 = x + w; |
| |
| /* Yellow box if we swapped textures */ |
| if ( mmesa->c_textureSwaps ) { |
| color = mach64PackColor( mmesa->mach64Screen->cpp, 255, 255, 0, 0 ); |
| |
| clear.x = x; |
| clear.y = y; |
| clear.w = w; |
| clear.h = h; |
| clear.clear_color = color; |
| |
| ret = drmCommandWrite( mmesa->driFd, DRM_MACH64_CLEAR, |
| &clear, sizeof(drm_mach64_clear_t) ); |
| |
| if (ret < 0) { |
| UNLOCK_HARDWARE( mmesa ); |
| fprintf( stderr, "DRM_MACH64_CLEAR: return = %d\n", ret ); |
| exit( -1 ); |
| } |
| |
| } |
| |
| h = 4; |
| x += 8; |
| b[0].x1 = x; |
| b[0].y2 = y + h; |
| |
| /* Purple bar for card memory texture blits/uploads */ |
| if ( mmesa->c_textureBytes ) { |
| color = mach64PackColor( mmesa->mach64Screen->cpp, 255, 0, 255, 0 ); |
| w = mmesa->c_textureBytes / 16384; |
| if ( w <= 0 ) |
| w = 1; |
| if (w > (mmesa->driDrawable->w - 44)) |
| w = mmesa->driDrawable->w - 44; |
| |
| b[0].x2 = x + w; |
| |
| clear.x = x; |
| clear.y = y; |
| clear.w = w; |
| clear.h = h; |
| clear.clear_color = color; |
| |
| ret = drmCommandWrite( mmesa->driFd, DRM_MACH64_CLEAR, |
| &clear, sizeof(drm_mach64_clear_t) ); |
| |
| if (ret < 0) { |
| UNLOCK_HARDWARE( mmesa ); |
| fprintf( stderr, "DRM_MACH64_CLEAR: return = %d\n", ret ); |
| exit( -1 ); |
| } |
| } |
| |
| /* Blue bar for AGP memory texture blits/uploads */ |
| if ( mmesa->c_agpTextureBytes ) { |
| color = mach64PackColor( mmesa->mach64Screen->cpp, 0, 0, 255, 0 ); |
| w = mmesa->c_agpTextureBytes / 16384; |
| if ( w <= 0 ) |
| w = 1; |
| if (w > (mmesa->driDrawable->w - 44)) |
| w = mmesa->driDrawable->w - 44; |
| |
| y += 4; |
| b[0].x2 = x + w; |
| b[0].y1 = y; |
| b[0].y2 = y + h; |
| |
| clear.x = x; |
| clear.y = y; |
| clear.w = w; |
| clear.h = h; |
| clear.clear_color = color; |
| |
| ret = drmCommandWrite( mmesa->driFd, DRM_MACH64_CLEAR, |
| &clear, sizeof(drm_mach64_clear_t) ); |
| |
| if (ret < 0) { |
| UNLOCK_HARDWARE( mmesa ); |
| fprintf( stderr, "DRM_MACH64_CLEAR: return = %d\n", ret ); |
| exit( -1 ); |
| } |
| } |
| |
| /* Pink bar for number of vertex buffers used */ |
| if ( mmesa->c_vertexBuffers ) { |
| color = mach64PackColor( mmesa->mach64Screen->cpp, 196, 128, 128, 0 ); |
| |
| w = mmesa->c_vertexBuffers; |
| if (w > (mmesa->driDrawable->w)) |
| w = mmesa->driDrawable->w; |
| |
| h = 8; |
| x = mmesa->drawX; |
| y = mmesa->drawY + 8; |
| b[0].x1 = x; |
| b[0].x2 = x + w; |
| b[0].y1 = y; |
| b[0].y2 = y + h; |
| |
| clear.x = x; |
| clear.y = y; |
| clear.w = w; |
| clear.h = h; |
| clear.clear_color = color; |
| |
| ret = drmCommandWrite( mmesa->driFd, DRM_MACH64_CLEAR, |
| &clear, sizeof(drm_mach64_clear_t) ); |
| |
| if (ret < 0) { |
| UNLOCK_HARDWARE( mmesa ); |
| fprintf( stderr, "DRM_MACH64_CLEAR: return = %d\n", ret ); |
| exit( -1 ); |
| } |
| } |
| |
| /* restore cliprects */ |
| mmesa->sarea->nbox = nbox; |
| b[0].x1 = x1; |
| b[0].y1 = y1; |
| b[0].x2 = x2; |
| b[0].y2 = y2; |
| |
| } |
| |
| #endif |
| |
| /* ================================================================ |
| * Buffer clear |
| */ |
| |
| static void mach64DDClear( GLcontext *ctx, GLbitfield mask ) |
| { |
| mach64ContextPtr mmesa = MACH64_CONTEXT( ctx ); |
| __DRIdrawablePrivate *dPriv = mmesa->driDrawable; |
| drm_mach64_clear_t clear; |
| GLuint flags = 0; |
| GLint i; |
| GLint ret; |
| GLint cx, cy, cw, ch; |
| |
| if ( MACH64_DEBUG & DEBUG_VERBOSE_API ) { |
| fprintf( stderr, "mach64DDClear\n"); |
| } |
| |
| #if ENABLE_PERF_BOXES |
| /* Bump the performance counter */ |
| mmesa->c_clears++; |
| #endif |
| |
| FLUSH_BATCH( mmesa ); |
| |
| /* The only state changes we care about here are the RGBA colormask |
| * and scissor/clipping. We'll just update that state, if needed. |
| */ |
| if ( mmesa->new_state & (MACH64_NEW_MASKS | MACH64_NEW_CLIP) ) { |
| const GLuint save_state = mmesa->new_state; |
| mmesa->new_state &= (MACH64_NEW_MASKS | MACH64_NEW_CLIP); |
| mach64DDUpdateHWState( ctx ); |
| mmesa->new_state = save_state & ~(MACH64_NEW_MASKS | MACH64_NEW_CLIP); |
| } |
| |
| if ( mask & BUFFER_BIT_FRONT_LEFT ) { |
| flags |= MACH64_FRONT; |
| mask &= ~BUFFER_BIT_FRONT_LEFT; |
| } |
| |
| if ( mask & BUFFER_BIT_BACK_LEFT ) { |
| flags |= MACH64_BACK; |
| mask &= ~BUFFER_BIT_BACK_LEFT; |
| } |
| |
| if ( ( mask & BUFFER_BIT_DEPTH ) && ctx->Depth.Mask ) { |
| flags |= MACH64_DEPTH; |
| mask &= ~BUFFER_BIT_DEPTH; |
| } |
| |
| if ( mask ) |
| _swrast_Clear( ctx, mask ); |
| |
| if ( !flags ) |
| return; |
| |
| 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; |
| |
| /* Flip top to bottom */ |
| cx += mmesa->drawX; |
| cy = mmesa->drawY + dPriv->h - cy - ch; |
| |
| /* HACK? |
| */ |
| if ( mmesa->dirty & ~MACH64_UPLOAD_CLIPRECTS ) { |
| mach64EmitHwStateLocked( mmesa ); |
| } |
| |
| for ( i = 0 ; i < mmesa->numClipRects ; ) { |
| int nr = MIN2( i + MACH64_NR_SAREA_CLIPRECTS, mmesa->numClipRects ); |
| drm_clip_rect_t *box = mmesa->pClipRects; |
| drm_clip_rect_t *b = mmesa->sarea->boxes; |
| GLint 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++; |
| } |
| } |
| |
| mmesa->sarea->nbox = n; |
| |
| if ( MACH64_DEBUG & DEBUG_VERBOSE_IOCTL ) { |
| fprintf( stderr, |
| "DRM_MACH64_CLEAR: flag 0x%x color %x depth %x nbox %d\n", |
| flags, |
| (GLuint)mmesa->ClearColor, |
| (GLuint)mmesa->ClearDepth, |
| mmesa->sarea->nbox ); |
| } |
| |
| clear.flags = flags; |
| clear.x = cx; |
| clear.y = cy; |
| clear.w = cw; |
| clear.h = ch; |
| clear.clear_color = mmesa->ClearColor; |
| clear.clear_depth = mmesa->ClearDepth; |
| |
| ret = drmCommandWrite( mmesa->driFd, DRM_MACH64_CLEAR, |
| &clear, sizeof(drm_mach64_clear_t) ); |
| |
| if ( ret ) { |
| UNLOCK_HARDWARE( mmesa ); |
| fprintf( stderr, "DRM_MACH64_CLEAR: return = %d\n", ret ); |
| exit( -1 ); |
| } |
| } |
| |
| UNLOCK_HARDWARE( mmesa ); |
| |
| mmesa->dirty |= (MACH64_UPLOAD_CONTEXT | |
| MACH64_UPLOAD_MISC | |
| MACH64_UPLOAD_CLIPRECTS); |
| |
| } |
| |
| |
| void mach64WaitForIdleLocked( mach64ContextPtr mmesa ) |
| { |
| int fd = mmesa->driFd; |
| int to = 0; |
| int ret; |
| |
| do { |
| ret = drmCommandNone( fd, DRM_MACH64_IDLE ); |
| } while ( ( ret == -EBUSY ) && ( to++ < MACH64_TIMEOUT ) ); |
| |
| if ( ret < 0 ) { |
| drmCommandNone( fd, DRM_MACH64_RESET ); |
| UNLOCK_HARDWARE( mmesa ); |
| fprintf( stderr, "Error: Mach64 timed out... exiting\n" ); |
| exit( -1 ); |
| } |
| } |
| |
| /* Flush the DMA queue to the hardware */ |
| void mach64FlushDMALocked( mach64ContextPtr mmesa ) |
| { |
| int fd = mmesa->driFd; |
| int ret; |
| |
| ret = drmCommandNone( fd, DRM_MACH64_FLUSH ); |
| |
| if ( ret < 0 ) { |
| drmCommandNone( fd, DRM_MACH64_RESET ); |
| UNLOCK_HARDWARE( mmesa ); |
| fprintf( stderr, "Error flushing DMA... exiting\n" ); |
| exit( -1 ); |
| } |
| |
| mmesa->dirty |= (MACH64_UPLOAD_CONTEXT | |
| MACH64_UPLOAD_MISC | |
| MACH64_UPLOAD_CLIPRECTS); |
| |
| } |
| |
| /* For client-side state emits - currently unused */ |
| void mach64UploadHwStateLocked( mach64ContextPtr mmesa ) |
| { |
| drm_mach64_sarea_t *sarea = mmesa->sarea; |
| |
| drm_mach64_context_regs_t *regs = &sarea->context_state; |
| unsigned int dirty = sarea->dirty; |
| CARD32 offset = ((regs->tex_size_pitch & 0xf0) >> 2); |
| |
| DMALOCALS; |
| |
| DMAGETPTR( 19*2 ); |
| |
| if ( dirty & MACH64_UPLOAD_MISC ) { |
| DMAOUTREG( MACH64_DP_MIX, regs->dp_mix ); |
| DMAOUTREG( MACH64_DP_SRC, regs->dp_src ); |
| DMAOUTREG( MACH64_CLR_CMP_CNTL, regs->clr_cmp_cntl ); |
| DMAOUTREG( MACH64_GUI_TRAJ_CNTL, regs->gui_traj_cntl ); |
| DMAOUTREG( MACH64_SC_LEFT_RIGHT, regs->sc_left_right ); |
| DMAOUTREG( MACH64_SC_TOP_BOTTOM, regs->sc_top_bottom ); |
| sarea->dirty &= ~MACH64_UPLOAD_MISC; |
| } |
| |
| if ( dirty & MACH64_UPLOAD_DST_OFF_PITCH ) { |
| DMAOUTREG( MACH64_DST_OFF_PITCH, regs->dst_off_pitch ); |
| sarea->dirty &= ~MACH64_UPLOAD_DST_OFF_PITCH; |
| } |
| if ( dirty & MACH64_UPLOAD_Z_OFF_PITCH ) { |
| DMAOUTREG( MACH64_Z_OFF_PITCH, regs->z_off_pitch ); |
| sarea->dirty &= ~MACH64_UPLOAD_Z_OFF_PITCH; |
| } |
| if ( dirty & MACH64_UPLOAD_Z_ALPHA_CNTL ) { |
| DMAOUTREG( MACH64_Z_CNTL, regs->z_cntl ); |
| DMAOUTREG( MACH64_ALPHA_TST_CNTL, regs->alpha_tst_cntl ); |
| sarea->dirty &= ~MACH64_UPLOAD_Z_ALPHA_CNTL; |
| } |
| if ( dirty & MACH64_UPLOAD_SCALE_3D_CNTL ) { |
| DMAOUTREG( MACH64_SCALE_3D_CNTL, regs->scale_3d_cntl ); |
| sarea->dirty &= ~MACH64_UPLOAD_SCALE_3D_CNTL; |
| } |
| if ( dirty & MACH64_UPLOAD_DP_FOG_CLR ) { |
| DMAOUTREG( MACH64_DP_FOG_CLR, regs->dp_fog_clr ); |
| sarea->dirty &= ~MACH64_UPLOAD_DP_FOG_CLR; |
| } |
| if ( dirty & MACH64_UPLOAD_DP_WRITE_MASK ) { |
| DMAOUTREG( MACH64_DP_WRITE_MASK, regs->dp_write_mask ); |
| sarea->dirty &= ~MACH64_UPLOAD_DP_WRITE_MASK; |
| } |
| if ( dirty & MACH64_UPLOAD_DP_PIX_WIDTH ) { |
| DMAOUTREG( MACH64_DP_PIX_WIDTH, regs->dp_pix_width ); |
| sarea->dirty &= ~MACH64_UPLOAD_DP_PIX_WIDTH; |
| } |
| if ( dirty & MACH64_UPLOAD_SETUP_CNTL ) { |
| DMAOUTREG( MACH64_SETUP_CNTL, regs->setup_cntl ); |
| sarea->dirty &= ~MACH64_UPLOAD_SETUP_CNTL; |
| } |
| |
| if ( dirty & MACH64_UPLOAD_TEXTURE ) { |
| DMAOUTREG( MACH64_TEX_SIZE_PITCH, regs->tex_size_pitch ); |
| DMAOUTREG( MACH64_TEX_CNTL, regs->tex_cntl ); |
| DMAOUTREG( MACH64_SECONDARY_TEX_OFF, regs->secondary_tex_off ); |
| DMAOUTREG( MACH64_TEX_0_OFF + offset, regs->tex_offset ); |
| sarea->dirty &= ~MACH64_UPLOAD_TEXTURE; |
| } |
| |
| #if 0 |
| if ( dirty & MACH64_UPLOAD_CLIPRECTS ) { |
| DMAOUTREG( MACH64_SC_LEFT_RIGHT, regs->sc_left_right ); |
| DMAOUTREG( MACH64_SC_TOP_BOTTOM, regs->sc_top_bottom ); |
| sarea->dirty &= ~MACH64_UPLOAD_CLIPRECTS; |
| } |
| #endif |
| |
| sarea->dirty = 0; |
| |
| DMAADVANCE(); |
| } |
| |
| void mach64InitIoctlFuncs( struct dd_function_table *functions ) |
| { |
| functions->Clear = mach64DDClear; |
| } |