mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
374 lines
13 KiB
374 lines
13 KiB
/******************************Module*Header*******************************\
|
|
* Module Name: dci.c
|
|
*
|
|
* This module contains the functions required to support DCI.
|
|
*
|
|
* Copyright (c) 1992-1995 Microsoft Corporation
|
|
\**************************************************************************/
|
|
|
|
|
|
#include "precomp.h"
|
|
|
|
#if (TARGET_BUILD == 351)
|
|
/*
|
|
* DCI support requires the use of structures and defined values
|
|
* found in a header file that is only present in versions of
|
|
* the DDK that support DCI, rather than having these items
|
|
* in a DCI section of one of the standard header files. For this
|
|
* reason, we can't do conditional compilation based on whether
|
|
* the DCI-specific values are defined, because our first indication
|
|
* would be an error due to the header file not being found.
|
|
*
|
|
* Explicit DCI support is only needed when building for NT 3.51,
|
|
* since it was added for this version, but for version 4.0 (next
|
|
* version) and above it is incorporated into Direct Draw rather
|
|
* than being handled separately.
|
|
*
|
|
* Since this entire module depends on DCI being supported by the
|
|
* build environment, null it out if this is not the case.
|
|
*/
|
|
#include <dciddi.h>
|
|
#include "dci.h"
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DCIRVAL BeginAccess
|
|
*
|
|
* Map in the screen memory so that the DCI application can access it.
|
|
|
|
\**************************************************************************/
|
|
|
|
DCIRVAL BeginAccess(DCISURF* pDCISurf, LPRECT rcl)
|
|
{
|
|
PDEV* ppdev;
|
|
VIDEO_SHARE_MEMORY shareMemory;
|
|
VIDEO_SHARE_MEMORY_INFORMATION shareMemoryInformation;
|
|
DWORD returnedDataLength;
|
|
|
|
DISPDBG((DEBUG_ENTRY_EXIT, "--> BeginAccess with pDCISurf %08lx", pDCISurf));
|
|
|
|
ppdev = pDCISurf->ppdev;
|
|
|
|
if (pDCISurf->SurfaceInfo.dwOffSurface != 0)
|
|
{
|
|
/*
|
|
* We have already mapped in the frame buffer. All our
|
|
* accelerators unmap the frame buffer in the
|
|
* DestroySurface() call, so if this is the beginning
|
|
* of the second or subsequent BeginAccess()/EndAccess()
|
|
* pair since the surface was created, we don't need to
|
|
* map the frame buffer again.
|
|
*
|
|
* Wait for any pending accelerator operations to complete before
|
|
* yielding control, in case it affects the same screen region
|
|
* that DCI wants.
|
|
*/
|
|
if (ppdev->iMachType == MACH_MM_64)
|
|
{
|
|
vM64QuietDown(ppdev, ppdev->pjMmBase);
|
|
}
|
|
else if (ppdev->iMachType == MACH_MM_32)
|
|
{
|
|
vM32QuietDown(ppdev, ppdev->pjMmBase);
|
|
}
|
|
else /* if (ppdev->iMachType == MACH_IO_32) */
|
|
{
|
|
vI32QuietDown(ppdev, ppdev->pjIoBase);
|
|
}
|
|
|
|
DISPDBG((DEBUG_ENTRY_EXIT, "<-- BeginAccess"));
|
|
return(DCI_OK);
|
|
}
|
|
else
|
|
{
|
|
shareMemory.ProcessHandle = EngGetProcessHandle();
|
|
shareMemory.RequestedVirtualAddress = 0;
|
|
shareMemory.ViewOffset = pDCISurf->Offset;
|
|
shareMemory.ViewSize = pDCISurf->Size;
|
|
|
|
/*
|
|
* Wait for any pending accelerator operations to complete
|
|
* before yielding control, in case it affects the same
|
|
* screen region that DCI wants.
|
|
*/
|
|
if (ppdev->iMachType == MACH_MM_64)
|
|
{
|
|
vM64QuietDown(ppdev, ppdev->pjMmBase);
|
|
}
|
|
else if (ppdev->iMachType == MACH_MM_32)
|
|
{
|
|
vM32QuietDown(ppdev, ppdev->pjMmBase);
|
|
}
|
|
else /* if (ppdev->iMachType == MACH_IO_32) */
|
|
{
|
|
vI32QuietDown(ppdev, ppdev->pjIoBase);
|
|
}
|
|
|
|
/*
|
|
* Now map the frame buffer into the caller's address space:
|
|
*
|
|
* Be careful when mixing VideoPortMapBankedMemory (i.e., vflatd)
|
|
* access with explicit banking in the driver -- the two may get
|
|
* out of sync with respect to what bank they think the hardware
|
|
* is currently configured for. The easiest way to avoid any
|
|
* problem is to call VideoPortMapBankedMemory/VideoPortUnmapMemory
|
|
* in the miniport for every BeginAccess/EndAccess pair, and to
|
|
* always explicitly reset the bank after the EndAccess.
|
|
* (VideoPortMapBankedMemory will always reset vflatd's current
|
|
* bank.)
|
|
*/
|
|
if (!AtiDeviceIoControl(pDCISurf->ppdev->hDriver,
|
|
IOCTL_VIDEO_SHARE_VIDEO_MEMORY,
|
|
&shareMemory,
|
|
sizeof(VIDEO_SHARE_MEMORY),
|
|
&shareMemoryInformation,
|
|
sizeof(VIDEO_SHARE_MEMORY_INFORMATION),
|
|
&returnedDataLength))
|
|
{
|
|
DISPDBG((DEBUG_ERROR, "BeginAccess: failed IOCTL_VIDEO_SHARE_VIDEO_MEMORY"));
|
|
return(DCI_FAIL_GENERIC);
|
|
}
|
|
|
|
pDCISurf->SurfaceInfo.wSelSurface = 0;
|
|
pDCISurf->SurfaceInfo.dwOffSurface =
|
|
(ULONG) shareMemoryInformation.VirtualAddress;
|
|
|
|
/*
|
|
* We return DCI_STATUS_POINTERCHANGED because we have
|
|
* just created a new pointer to the frame buffer.
|
|
* Repeated BeginAccess()/EndAccess() calls without
|
|
* a call to DestroySurface() will hit this case on the
|
|
* first call, but meet the "if" condition (buffer
|
|
* already mapped) on subsequent calls.
|
|
*
|
|
* We would only need to map the DCI pointer on every
|
|
* call to BeginAccess() and unmap it on every call
|
|
* to EndAccess() if we couldn't support simultaneous
|
|
* accelerator and frame buffer access. All our cards
|
|
* with frame buffer capability support such access,
|
|
* and it's GDI's responsibility to ensure that no
|
|
* GDI call is made between the calls to BeginAccess()
|
|
* and EndAccess(), so we don't need a critical section
|
|
* to ensure that a GDI call doesn't change the page
|
|
* while DCI is accessing the frame buffer if we are
|
|
* using a banked aperture.
|
|
*/
|
|
#if DBG
|
|
DISPDBG((DEBUG_ENTRY_EXIT, "<-- BeginAccess DCI_STATUS_POINTERCHANGED %08lx\n", pDCISurf));
|
|
#endif
|
|
|
|
return(DCI_STATUS_POINTERCHANGED);
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vUnmap
|
|
*
|
|
* Unmap the screen memory so that the DCI application can no longer access
|
|
* it.
|
|
|
|
\**************************************************************************/
|
|
|
|
VOID vUnmap(DCISURF* pDCISurf)
|
|
{
|
|
PDEV* ppdev;
|
|
VIDEO_SHARE_MEMORY shareMemory;
|
|
DWORD returnedDataLength;
|
|
|
|
ppdev = pDCISurf->ppdev;
|
|
|
|
/*
|
|
* We no longer need to have the frame buffer mapped for DCI,
|
|
* so unmap it.
|
|
*/
|
|
shareMemory.ProcessHandle = EngGetProcessHandle();
|
|
shareMemory.ViewOffset = 0;
|
|
shareMemory.ViewSize = 0;
|
|
shareMemory.RequestedVirtualAddress =
|
|
(VOID*) pDCISurf->SurfaceInfo.dwOffSurface;
|
|
|
|
if (!AtiDeviceIoControl(pDCISurf->ppdev->hDriver,
|
|
IOCTL_VIDEO_UNSHARE_VIDEO_MEMORY,
|
|
&shareMemory,
|
|
sizeof(VIDEO_SHARE_MEMORY),
|
|
NULL,
|
|
0,
|
|
&returnedDataLength))
|
|
{
|
|
DISPDBG((DEBUG_ERROR, "EndAccess failed IOCTL_VIDEO_UNSHARE_VIDEO_MEMORY"));
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Be sure to signal to GDI that the surface is no longer mapped.
|
|
*/
|
|
pDCISurf->SurfaceInfo.dwOffSurface = 0;
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DCIRVAL EndAccess
|
|
*
|
|
* Switch control of the frame buffer from DCI back to GDI.
|
|
\**************************************************************************/
|
|
|
|
DCIRVAL EndAccess(DCISURF* pDCISurf)
|
|
{
|
|
PDEV* ppdev;
|
|
|
|
/*
|
|
* We would only need to unmap the frame buffer at this
|
|
* point if our cards couldn't support simultaneous frame
|
|
* buffer and accelerator access. Since our cards with
|
|
* frame buffer capability all support such access (provided
|
|
* the two accesses refer to different parts of the screen,
|
|
* since otherwise they'd corrupt each other, but it's
|
|
* GDI's responsibility to ensure that this is the case),
|
|
* this function only needs to ensure that no call to
|
|
* EndAccess() is made without a corresponding call to
|
|
* BeginAccess() having already been made.
|
|
*/
|
|
|
|
DISPDBG((DEBUG_ENTRY_EXIT, "EndAccess with pDCISurf %08lx\n", pDCISurf));
|
|
|
|
ASSERTDD(pDCISurf->SurfaceInfo.dwOffSurface != 0,
|
|
"GDI should assure us that EndAccess can't be recursive");
|
|
|
|
ppdev = pDCISurf->ppdev;
|
|
|
|
return(DCI_OK);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID DestroySurface
|
|
*
|
|
* Destroy the DCI surface and free up any allocations.
|
|
|
|
\**************************************************************************/
|
|
|
|
VOID DestroySurface(DCISURF* pDCISurf)
|
|
{
|
|
DISPDBG((DEBUG_ENTRY_EXIT, "DestroySurface with pDCISurf %08lx\n", pDCISurf));
|
|
|
|
if (pDCISurf->SurfaceInfo.dwOffSurface != 0)
|
|
{
|
|
/*
|
|
* Because we can support simultaneous frame buffer and
|
|
* accelerator access, we optimized a bit by not unmapping
|
|
* the frame buffer on every EndAccess() call, but we
|
|
* finally have to do the unmap now. The dwOffSurface field
|
|
* should always be nonzero (a frame buffer has been mapped),
|
|
* but there's no harm in checking.
|
|
*/
|
|
vUnmap(pDCISurf);
|
|
}
|
|
|
|
LocalFree(pDCISurf);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* ULONG DCICreatePrimarySurface
|
|
*
|
|
* Create a DCI surface to provide access to the visible screen.
|
|
|
|
\**************************************************************************/
|
|
|
|
ULONG DCICreatePrimarySurface(PDEV* ppdev, ULONG cjIn, VOID* pvIn, ULONG cjOut, VOID* pvOut)
|
|
{
|
|
DCISURF* pDCISurf;
|
|
LPDCICREATEINPUT pInput;
|
|
LONG lRet;
|
|
|
|
|
|
#if defined(MIPS) || defined(_PPC_)
|
|
{
|
|
/*
|
|
* !!! vflatd seems to currently have a bug on Mips and PowerPC:
|
|
*/
|
|
return (ULONG) (DCI_FAIL_UNSUPPORTED);
|
|
}
|
|
#endif
|
|
|
|
if( !(ppdev->FeatureFlags & EVN_DENSE_CAPABLE) )
|
|
{
|
|
/*
|
|
* We don't support DCI on the Alpha when running in sparse
|
|
* space, because we can't.
|
|
*/
|
|
lRet = DCI_FAIL_UNSUPPORTED;
|
|
}
|
|
else
|
|
{
|
|
pInput = (DCICREATEINPUT*) pvIn;
|
|
|
|
if (cjIn >= sizeof(DCICREATEINPUT))
|
|
{
|
|
pDCISurf = (DCISURF*) LocalAlloc(LMEM_ZEROINIT, sizeof(DCISURF));
|
|
|
|
if (pDCISurf)
|
|
{
|
|
/*
|
|
* Initializate all public information about the primary
|
|
* surface.
|
|
*/
|
|
pDCISurf->SurfaceInfo.dwSize = sizeof(DCISURFACEINFO);
|
|
pDCISurf->SurfaceInfo.dwDCICaps = DCI_PRIMARY | DCI_VISIBLE;
|
|
pDCISurf->SurfaceInfo.BeginAccess = BeginAccess;
|
|
pDCISurf->SurfaceInfo.EndAccess = EndAccess;
|
|
pDCISurf->SurfaceInfo.DestroySurface = DestroySurface;
|
|
pDCISurf->SurfaceInfo.dwMask[0] = ppdev->flRed;
|
|
pDCISurf->SurfaceInfo.dwMask[1] = ppdev->flGreen;
|
|
pDCISurf->SurfaceInfo.dwMask[2] = ppdev->flBlue;
|
|
pDCISurf->SurfaceInfo.dwBitCount = ppdev->cBitsPerPel;
|
|
pDCISurf->SurfaceInfo.dwWidth = ppdev->cxScreen;
|
|
pDCISurf->SurfaceInfo.dwHeight = ppdev->cyScreen;
|
|
pDCISurf->SurfaceInfo.lStride = ppdev->lDelta;
|
|
pDCISurf->SurfaceInfo.wSelSurface = 0;
|
|
pDCISurf->SurfaceInfo.dwOffSurface = 0;
|
|
|
|
if (pDCISurf->SurfaceInfo.dwBitCount <= 8)
|
|
{
|
|
pDCISurf->SurfaceInfo.dwCompression = BI_RGB;
|
|
}
|
|
else
|
|
{
|
|
pDCISurf->SurfaceInfo.dwCompression = BI_BITFIELDS;
|
|
}
|
|
|
|
/*
|
|
* Now initialize our private fields that we want associated
|
|
* with the DCI surface:
|
|
*/
|
|
pDCISurf->ppdev = ppdev;
|
|
pDCISurf->Offset = 0;
|
|
|
|
/*
|
|
* Under NT, all mapping is done with a 64K granularity.
|
|
*/
|
|
pDCISurf->Size = ROUND_UP_TO_64K(ppdev->cyScreen * ppdev->lDelta);
|
|
|
|
/*
|
|
* Return a pointer to the DCISURF to GDI by placing
|
|
* it in the 'pvOut' buffer.
|
|
*/
|
|
*((DCISURF**) pvOut) = pDCISurf;
|
|
|
|
lRet = DCI_OK;
|
|
}
|
|
else
|
|
{
|
|
lRet = DCI_ERR_OUTOFMEMORY;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lRet = DCI_FAIL_GENERIC;
|
|
}
|
|
}
|
|
|
|
return(lRet);
|
|
}
|
|
|
|
#endif /* TARGET_BUILD == 351 */
|
|
|
|
|