/******************************Module*Header**********************************\ * * ************************* * * GDI/DDRAW SAMPLE CODE * * ************************* * * Module Name: ddraw.c * * Content: Provides interfaces back from the DDRAW .lib file into the main NT driver * * Copyright (c) 1994-1999 3Dlabs Inc. Ltd. All rights reserved. * Copyright (c) 1995-2003 Microsoft Corporation. All rights reserved. \*****************************************************************************/ #include "precomp.h" #include "glint.h" #if WNT_DDRAW // The code inside this WNT_DDRAW ifdef is code that interfaces between the DirectDraw // core (as ported from Win 95) and the Win NT display driver. /* * vNTSyncWith2DDriver () * -------------------------- * * Sync DirectDraw with every other subsystem: 2D driver . We * put it in a function to get at the correct data structures. */ VOID vNTSyncWith2DDriver(PPDEV ppdev) { GLINT_DECL; SYNC_WITH_GLINT; } // if we're expecting to use the vblank interrupt but the adapter hasn't been allocated an // interrupt, we'll need to provide temporary storage for values that would otherwise have been // stored within the interrupt block ULONG gulOverlayEnabled; ULONG gulVBLANKUpdateOverlay; ULONG gulVBLANKUpdateOverlayWidth; ULONG gulVBLANKUpdateOverlayHeight; /* * bSetupOffscreenForDDraw () * -------------------------- * * This function enables and disables the Display Driver's off-screen video memory. * This allows DirectDraw to take control of the off-screen memory and to * create it's linear heap in the memory. * * Note: only implemented for Permedia. */ BOOL bSetupOffscreenForDDraw( BOOL enableFlag, PPDEV ppdev, volatile DWORD **VBlankAddress, volatile DWORD **bOverlayEnabled, volatile DWORD **VBLANKUpdateOverlay, volatile DWORD **VBLANKUpdateOverlayWidth, volatile DWORD **VBLANKUpdateOverlayHeight) { BOOL retVal = TRUE; PINTERRUPT_CONTROL_BLOCK pBlock; GLINT_DECL; DISPDBG((DBGLVL, "bSetupOffscreenForDDraw: in addr 0x%x", VBlankAddress)); if (enableFlag) { if((ppdev->flStatus & STAT_LINEAR_HEAP) == 0) { // disabling DDraw, reenabling 2D offscreeen vEnable2DOffscreenMemory(ppdev); } // Get pointer to interrupt command block pBlock = glintInfo->pInterruptCommandBlock; // Reset the interrupt flags if (INTERRUPTS_ENABLED && (pBlock->Control & DIRECTDRAW_VBLANK_ENABLED)) { // Clear the flag to stop the interrupt routine setting the // flag in the shared structure pBlock->Control &= ~DIRECTDRAW_VBLANK_ENABLED; // clear VBLANK flag or we'll get an immediate interrupt WRITE_GLINT_CTRL_REG(IntFlags, INTR_CLEAR_VBLANK); // Re-instate the original flags WRITE_GLINT_CTRL_REG(IntEnable, ppdev->oldIntEnableFlags); } } else { // enabling DDraw, disabling 2D offscreen // We zap off-screen memory chunks on Permedia, only if there // aren't any OGL apps running. { // There aren't any OGL apps running, so grab all the // memory for DDraw if(ppdev->flStatus & ENABLE_LINEAR_HEAP) { // DX managed linear heap - we don't need to do anything // NB. check against whether we have the capability to use the linear heap, rather than // whether it's currently enabled as it's only enabled much later, in DrvNotify retVal = TRUE; } else retVal = bDisable2DOffscreenMemory(ppdev); if (retVal == TRUE) { // We return a pointer to a 'long' which DirectDraw can // poll to see if it is zero or not. if (VBlankAddress != NULL) { DWORD enableFlags; *VBlankAddress = NULL; if (INTERRUPTS_ENABLED) { // Get pointer to interrupt command block pBlock = glintInfo->pInterruptCommandBlock; // Indicate that we require the miniport to // set a flag for us pBlock->Control |= DIRECTDRAW_VBLANK_ENABLED; // clear VBLANK flag or we'll get an immediate interrupt WRITE_GLINT_CTRL_REG(IntFlags, INTR_CLEAR_VBLANK); // enable the VBLANK interrupt READ_GLINT_CTRL_REG (IntEnable, enableFlags); WRITE_GLINT_CTRL_REG(IntEnable, enableFlags | INTR_ENABLE_VBLANK); // Save the old interrupt flags so that we can restore them ppdev->oldIntEnableFlags = enableFlags; // Set up pointers into the shared memory *VBlankAddress = &pBlock->DDRAW_VBLANK; *bOverlayEnabled = &pBlock->bOverlayEnabled; *VBLANKUpdateOverlay = &pBlock->bVBLANKUpdateOverlay; *VBLANKUpdateOverlayWidth = &pBlock->VBLANKUpdateOverlayWidth; *VBLANKUpdateOverlayHeight = &pBlock->VBLANKUpdateOverlayHeight; } else { *bOverlayEnabled = &gulOverlayEnabled; *VBLANKUpdateOverlay = &gulVBLANKUpdateOverlay; *VBLANKUpdateOverlayWidth = &gulVBLANKUpdateOverlayWidth; *VBLANKUpdateOverlayHeight = &gulVBLANKUpdateOverlayHeight; } DISPDBG((DBGLVL, "bSetupOffscreenForDDraw: configured ptr 0x%x", *VBlankAddress)); } } } } DISPDBG((DBGLVL, "bSetupOffscreenForDDraw: exit %d", retVal)); return (retVal); } /* * GetChipInfoForDDraw () * ---------------------- * * A simple helper function to return chip information to DirectDraw */ VOID GetChipInfoForDDraw( PPDEV ppdev, DWORD* pdwChipID, DWORD* pdwChipRev, DWORD* pdwChipFamily, DWORD* pdwGammaRev) { GLINT_DECL; DISPDBG((DBGLVL,"*** In GetChipInfoForDDraw")); DISPDBG((DBGLVL," Chip is PXRX Family")); *pdwChipFamily = PERMEDIA3_ID; *pdwChipID = glintInfo->deviceInfo.DeviceId; *pdwChipRev = glintInfo->deviceInfo.RevisionId; *pdwGammaRev = glintInfo->deviceInfo.GammaRevId; } /* * GetFBLBInfoForDDraw () * ---------------------- * * Return some basic framnebuffer/localbuffer info to DirectDraw. */ VOID GetFBLBInfoForDDraw( PPDEV ppdev, void **fbPtr, // Framebuffer pointer void **lbPtr, // Localbuffer pointer DWORD *fbSizeInBytes, // Size of framebuffer DWORD *lbSizeInBytes, // Size of localbuffer DWORD *fbOffsetInBytes, // Offset to 1st 'free' byte in framebuffer BOOL *bSDRAM) // TRUE if SDRAM (i.e. no h/w write mask) { GLINT_DECL; *fbPtr = ppdev->pjScreen; *lbPtr = NULL; // We don't know this one *fbSizeInBytes = ppdev->FrameBufferLength; *lbSizeInBytes = TEXTURE_MEMORY_SIZE; *fbOffsetInBytes = ppdev->heap.DDrawOffscreenStart * ppdev->cjPelSize; *bSDRAM = (GLINT_HW_WRITE_MASK == FALSE); DISPDBG((DBGLVL, "GetFBLBInfoForDDraw: offstart 0x%x, buf[1] 0x%lx, pelsz %d", ppdev->heap.DDrawOffscreenStart, GLINT_BUFFER_OFFSET(1), ppdev->cjPelSize)); } // DDSendDMAData // Uses DMA to transfer one complete buffer of DDRAW data // under NT5. // Before initiating DMA transfer, a check is made to ensure // that any previous DMA transfer has completed. // Then the DMA is initiated and the routine returns, so that // the DMA transfer proceeds in parallel with the processor's // proceeding execution. LONG DDSendDMAData( PDEV* ppdev, ULONG PhysAddr, ULONG_PTR VirtAddr, LONG nDataEntries) { ULONG frontIndex, nextIndex; volatile ULONG ulValue; GLINT_DECL ; // PhysAddr += DataOffset; // VirtAddr += DataOffset; DISPDBG((DBGLVL, "DMASendData: DMA at 0x%x for %d", PhysAddr, nDataEntries)); ppdev->g_GlintBoardStatus &= ~GLINT_DMA_COMPLETE; if (ppdev->g_GlintBoardStatus & GLINT_INTR_CONTEXT) { PINTERRUPT_CONTROL_BLOCK pBlock = glintInfo->pInterruptCommandBlock; DISPDBG((DBGLVL, "Processing buffer at 0x%x for %d", PhysAddr, nDataEntries)); DISPDBG((DBGLVL, "Adding buffer to Q")); frontIndex = pBlock->frontIndex; if ((nextIndex = frontIndex+1) == pBlock->endIndex) nextIndex = 0; // wait for a free queue entry. We should really do a backoff here. while (nextIndex == pBlock->backIndex); DISPDBG((DBGLVL, "Add to DMA Q backindex %d frontindex %d",frontIndex, pBlock->backIndex)); // add the DMA address and count to the new entry. pBlock->dmaQueue[frontIndex].address = PhysAddr; pBlock->dmaQueue[frontIndex].count = nDataEntries; pBlock->frontIndex = nextIndex; // wakeup the interrupt handler using an error interrupt. To save on // interrupt processing, only do this if a DMA interrupt is not // pending. // //if (!pBlock->InterruptPending) { DISPDBG((DBGLVL, "Generating error interrupt")); WRITE_GLINT_CTRL_REG(ErrorFlags, 0x7); // clear error flags READ_OUTPUT_FIFO(ulValue); // generate interrupt } } else { WAIT_IMMEDIATE_DMA_COMPLETE; SET_DMA_ADDRESS(PhysAddr, VirtAddr) ; SET_DMA_COUNT(nDataEntries); } DISPDBG((DBGLVL,"DMA count=%d\n", nDataEntries )) ; return 1 ; } // Wrapper function used for requesting a DMA memory buffer // from NT for use by D3D. NT 5 only. LONG DDGetFreeDMABuffer( DWORD *physAddr, ULONG_PTR *virtAddr, DWORD *bufferSize) { LONG BuffNum; QUERY_DMA_BUFFERS dmaBuffer; BuffNum = GetFreeDMABuffer(&dmaBuffer); if (BuffNum >= 0) { *physAddr = (DWORD)dmaBuffer.physAddr.LowPart; *virtAddr = (ULONG_PTR)dmaBuffer.virtAddr; *bufferSize = (DWORD)dmaBuffer.size; } else { // Failed to get a free DMA buffer *physAddr = 0; *virtAddr = 0; *bufferSize = 0; } return BuffNum; } // Frees the given DMA buffer. VOID DDFreeDMABuffer(void* pPhysAddress) { FreeDMABuffer(pPhysAddress); return; } LONG DDWaitDMAComplete(PDEV *ppdev) { GLINT_DECL ; WAIT_DMA_COMPLETE; return 0; } #endif WNT_DDRAW