mirror of
https://github.com/Cesarus85/ringfall-mjolnir-vr.git
synced 2026-10-26 20:01:13 +01:00
1276 lines
38 KiB
C++
1276 lines
38 KiB
C++
/* Additional device methods adapted from RXDK-Libs, 2026 Team Resurgent.
|
|
* GPL-3.0-or-later; see libs/d3d8/PROVENANCE.md. */
|
|
#include "device_layout.h"
|
|
#include "pixeljar.h"
|
|
#include "push_internal.h"
|
|
#include "resource_internal.h"
|
|
#include "display_internal.h"
|
|
#include "state_internal.h"
|
|
#include "math_internal.h"
|
|
#include "memory_internal.h"
|
|
#include "kernel_memory.h"
|
|
#include "visibility_internal.h"
|
|
#include "kernel_dispatcher.h"
|
|
#include "hardware_internal.h"
|
|
#include "surface_internal.h"
|
|
#pragma code_seg("D3D")
|
|
using namespace D3D;
|
|
void WINAPI D3DDevice_GetDirect3D(
|
|
Direct3D **direct3d)
|
|
{
|
|
*direct3d = (Direct3D *)1;
|
|
return;
|
|
}
|
|
void WINAPI D3DDevice_GetDeviceCaps(
|
|
D3DCAPS8 *caps)
|
|
{
|
|
*caps = g_DeviceCaps;
|
|
return;
|
|
}
|
|
void WINAPI D3DDevice_GetCreationParameters(
|
|
D3DDEVICE_CREATION_PARAMETERS *parameters)
|
|
{
|
|
CDevice *device = g_pDevice;
|
|
memset(parameters, 0, sizeof(*parameters));
|
|
parameters->DeviceType = D3DDEVTYPE_HAL;
|
|
parameters->BehaviorFlags |= D3DCREATE_HARDWARE_VERTEXPROCESSING;
|
|
if (device->m_StateFlags & 0x10)
|
|
{
|
|
parameters->BehaviorFlags |= D3DCREATE_PUREDEVICE;
|
|
}
|
|
return;
|
|
}
|
|
void WINAPI D3DDevice_SetGammaRamp(
|
|
DWORD flags,
|
|
const D3DGAMMARAMP *ramp)
|
|
{
|
|
CDevice *device = g_pDevice;
|
|
CMiniport *miniport = &device->m_Miniport;
|
|
DWORD index = device->m_PresentCount & 1;
|
|
D3DGAMMARAMP *destination = &miniport->m_GammaRamp[index];
|
|
*destination = *ramp;
|
|
miniport->m_GammaCurrentIndex = index;
|
|
if (flags & 2)
|
|
{
|
|
miniport->DacProgramGammaRamp(destination);
|
|
}
|
|
else
|
|
{
|
|
miniport->m_GammaUpdated[index] = TRUE;
|
|
}
|
|
return;
|
|
}
|
|
void WINAPI D3DDevice_GetGammaRamp(
|
|
D3DGAMMARAMP *ramp)
|
|
{
|
|
CDevice *device = g_pDevice;
|
|
*ramp = device->m_Miniport.m_GammaRamp[device->m_Miniport.m_GammaCurrentIndex];
|
|
return;
|
|
}
|
|
void WINAPI D3DDevice_GetTransform(
|
|
D3DTRANSFORMSTATETYPE state,
|
|
D3DMATRIX *matrix)
|
|
{
|
|
CDevice *device = g_pDevice;
|
|
*matrix = device->m_Transform[state];
|
|
return;
|
|
}
|
|
void WINAPI D3DDevice_GetViewport(
|
|
D3DVIEWPORT8 *viewport)
|
|
{
|
|
CDevice *device = g_pDevice;
|
|
*viewport = device->m_Viewport;
|
|
return;
|
|
}
|
|
void WINAPI D3DDevice_SetMaterial(
|
|
const D3DMATERIAL8 *material)
|
|
{
|
|
CDevice *device = g_pDevice;
|
|
device->m_Material = *material;
|
|
device->m_DirtyFlags |= 0x20;
|
|
return;
|
|
}
|
|
void WINAPI D3DDevice_GetMaterial(
|
|
D3DMATERIAL8 *material)
|
|
{
|
|
CDevice *device = g_pDevice;
|
|
*material = device->m_Material;
|
|
return;
|
|
}
|
|
void WINAPI D3DDevice_SetBackMaterial(
|
|
const D3DMATERIAL8 *material)
|
|
{
|
|
CDevice *device = g_pDevice;
|
|
device->m_BackMaterial = *material;
|
|
device->m_DirtyFlags |= 0x20;
|
|
return;
|
|
}
|
|
void WINAPI D3DDevice_GetBackMaterial(
|
|
D3DMATERIAL8 *material)
|
|
{
|
|
CDevice *device = g_pDevice;
|
|
*material = device->m_BackMaterial;
|
|
return;
|
|
}
|
|
void WINAPI D3DDevice_GetLight(
|
|
DWORD index,
|
|
D3DLIGHT8 *light)
|
|
{
|
|
CDevice *device = g_pDevice;
|
|
*light = device->m_pLights[index].Light8;
|
|
return;
|
|
}
|
|
void WINAPI D3DDevice_GetLightEnable(
|
|
DWORD index,
|
|
BOOL *enabled)
|
|
{
|
|
CDevice *device = g_pDevice;
|
|
Light *requested = &device->m_pLights[index];
|
|
Light *light = device->m_pActiveLights;
|
|
while (light)
|
|
{
|
|
if (light == requested)
|
|
{
|
|
*enabled = TRUE;
|
|
return;
|
|
}
|
|
light = light->pNext;
|
|
}
|
|
*enabled = FALSE;
|
|
return;
|
|
}
|
|
void WINAPI D3DDevice_SetVerticalBlankCallback(
|
|
D3DCALLBACK callback)
|
|
{
|
|
g_pDevice->m_Miniport.m_pVerticalBlankCallback = callback;
|
|
return;
|
|
}
|
|
void WINAPI D3DDevice_GetProjectionViewportMatrix(
|
|
D3DMATRIX *matrix)
|
|
{
|
|
*matrix = g_pDevice->m_ProjectionViewportTransform;
|
|
return;
|
|
}
|
|
HRESULT WINAPI D3DDevice_GetModelView(
|
|
D3DMATRIX *matrix)
|
|
{
|
|
CDevice *device = g_pDevice;
|
|
if (matrix)
|
|
{
|
|
*matrix = device->m_ModelViewTransform[0];
|
|
}
|
|
return !(device->m_DirtyFlags & 0x80000000);
|
|
}
|
|
void WINAPI D3DDevice_GetTile(
|
|
DWORD index,
|
|
D3DTILE *tile)
|
|
{
|
|
*tile = g_pDevice->m_Tile[index];
|
|
return;
|
|
}
|
|
void WINAPI D3DDevice_GetScissors(
|
|
DWORD *count,
|
|
BOOL *exclusive,
|
|
D3DRECT *rectangles)
|
|
{
|
|
CDevice *device = g_pDevice;
|
|
if (count)
|
|
{
|
|
*count = device->m_ScissorsCount;
|
|
}
|
|
if (exclusive)
|
|
{
|
|
*exclusive = device->m_ScissorsExclusive;
|
|
}
|
|
if (rectangles)
|
|
{
|
|
memcpy(rectangles, device->m_ScissorsRects, device->m_ScissorsCount * sizeof(*rectangles));
|
|
}
|
|
return;
|
|
}
|
|
|
|
HRESULT WINAPI D3DDevice_CreateTexture(
|
|
UINT width,
|
|
UINT height,
|
|
UINT levels,
|
|
DWORD usage,
|
|
D3DFORMAT format,
|
|
D3DPOOL pool,
|
|
D3DTexture **texture)
|
|
{
|
|
return CreateTexture(width, height, 1, levels, usage, format, false, false, (D3DBaseTexture **)texture);
|
|
}
|
|
HRESULT WINAPI D3DDevice_CreateVolumeTexture(
|
|
UINT width,
|
|
UINT height,
|
|
UINT depth,
|
|
UINT levels,
|
|
DWORD usage,
|
|
D3DFORMAT format,
|
|
D3DPOOL pool,
|
|
D3DVolumeTexture **texture)
|
|
{
|
|
return CreateTexture(width, height, depth, levels, usage, format, false, true, (D3DBaseTexture **)texture);
|
|
}
|
|
HRESULT WINAPI D3DDevice_CreateCubeTexture(
|
|
UINT edge,
|
|
UINT levels,
|
|
DWORD usage,
|
|
D3DFORMAT format,
|
|
D3DPOOL pool,
|
|
D3DCubeTexture **texture)
|
|
{
|
|
return CreateTexture(edge, edge, 1, levels, usage, format, true, false, (D3DBaseTexture **)texture);
|
|
}
|
|
HRESULT WINAPI D3DDevice_CreateRenderTarget(
|
|
UINT width,
|
|
UINT height,
|
|
D3DFORMAT format,
|
|
D3DMULTISAMPLE_TYPE multisample,
|
|
BOOL lockable,
|
|
D3DSurface **surface)
|
|
{
|
|
return CreateStandAloneSurface(width, height, format, true, surface);
|
|
}
|
|
HRESULT WINAPI D3DDevice_CreateDepthStencilSurface(
|
|
UINT width,
|
|
UINT height,
|
|
D3DFORMAT format,
|
|
D3DMULTISAMPLE_TYPE multisample,
|
|
D3DSurface **surface)
|
|
{
|
|
return CreateStandAloneSurface(width, height, format, true, surface);
|
|
}
|
|
HRESULT WINAPI D3DDevice_CreateImageSurface(
|
|
UINT width,
|
|
UINT height,
|
|
D3DFORMAT format,
|
|
D3DSurface **surface)
|
|
{
|
|
return CreateStandAloneSurface(width, height, format, false, surface);
|
|
}
|
|
void WINAPI D3DDevice_SetTransform(
|
|
D3DTRANSFORMSTATETYPE State,
|
|
const D3DMATRIX *pMatrix)
|
|
{
|
|
DWORD state = (DWORD)State;
|
|
CDevice *pDevice = g_pDevice;
|
|
pDevice->m_Transform[state] = *pMatrix;
|
|
pDevice->m_DirtyFlags |= g_TransformDirtyTable[state];
|
|
if (State == D3DTS_PROJECTION)
|
|
{
|
|
if (pMatrix->_33 == pMatrix->_34 || pMatrix->_33 == 0.0f)
|
|
{
|
|
pDevice->m_WNear = 0.0f;
|
|
pDevice->m_WFar = 1.0f;
|
|
}
|
|
else
|
|
{
|
|
pDevice->m_WNear = pMatrix->_44 - pMatrix->_43 / pMatrix->_33 * pMatrix->_34;
|
|
pDevice->m_WFar = (pMatrix->_44 - pMatrix->_43) / (pMatrix->_33 - pMatrix->_34) * pMatrix->_34 + pMatrix->_44;
|
|
}
|
|
pDevice->m_InverseWFar = 1.0f / pDevice->m_WFar;
|
|
pDevice->m_StateFlags &= ~2;
|
|
if (pMatrix->_14 == 0.0f && pMatrix->_24 == 0.0f && pMatrix->_34 == 0.0f && pMatrix->_44 == 1.0f)
|
|
{
|
|
pDevice->m_StateFlags |= 2;
|
|
}
|
|
UpdateProjectionViewportTransform();
|
|
CommonSetPassthroughProgram(pDevice);
|
|
}
|
|
return;
|
|
}
|
|
void WINAPI D3DDevice_MultiplyTransform(
|
|
D3DTRANSFORMSTATETYPE State,
|
|
const D3DMATRIX *pMatrix)
|
|
{
|
|
__declspec(align(16)) D3DMATRIX result;
|
|
__declspec(align(16)) D3DMATRIX temp = *pMatrix;
|
|
DWORD state = (DWORD)State;
|
|
CDevice *pDevice = g_pDevice;
|
|
MatrixProduct4x4(&result, &temp, &pDevice->m_Transform[state]);
|
|
D3DDevice_SetTransform(State, &result);
|
|
return;
|
|
}
|
|
ULONG WINAPI D3DDevice_AddRef(
|
|
void)
|
|
{
|
|
return ++g_pDevice->m_cRefs;
|
|
}
|
|
ULONG WINAPI D3DDevice_Release(
|
|
void)
|
|
{
|
|
CDevice *device = g_pDevice;
|
|
if (device->m_cRefs == 1)
|
|
{
|
|
device->UnInit();
|
|
g_pPushBuffer = NULL;
|
|
g_pDevice = NULL;
|
|
memset(device, 0, sizeof(*device));
|
|
return 0;
|
|
}
|
|
return --device->m_cRefs;
|
|
}
|
|
void WINAPI D3DDevice_BlockUntilIdle(
|
|
void)
|
|
{
|
|
KickOffAndWaitForIdle();
|
|
return;
|
|
}
|
|
void WINAPI D3DDevice_BlockOnFence(
|
|
DWORD fence)
|
|
{
|
|
BlockOnTime(fence, FALSE);
|
|
return;
|
|
}
|
|
void WINAPI D3DDevice_KickPushBuffer(
|
|
void)
|
|
{
|
|
g_pDevice->KickOff();
|
|
return;
|
|
}
|
|
DWORD WINAPI D3DDevice_InsertFence(
|
|
void)
|
|
{
|
|
return SetFence(0);
|
|
}
|
|
void WINAPI D3DDevice_GetDisplayMode(
|
|
D3DDISPLAYMODE *mode)
|
|
{
|
|
CDevice *device = g_pDevice;
|
|
mode->Width = device->m_DisplayWidth;
|
|
mode->Height = device->m_DisplayHeight;
|
|
mode->RefreshRate = device->m_Miniport.GetRefreshRate();
|
|
mode->Flags = CMiniport::GetPresentFlagsFromAvInfo(device->m_Miniport.m_CurrentAvInfo);
|
|
mode->Format = PixelJar::GetFormat(&device->m_FrameBufferSurfaces[1]);
|
|
return;
|
|
}
|
|
void WINAPI D3DDevice_GetBackBuffer(
|
|
INT BackBuffer,
|
|
D3DBACKBUFFER_TYPE Type,
|
|
D3DSurface **surface)
|
|
{
|
|
CDevice *device = g_pDevice;
|
|
if (BackBuffer == -1) { BackBuffer = 1; }
|
|
else if (BackBuffer) { ++BackBuffer; }
|
|
*surface = &device->m_FrameBufferSurfaces[BackBuffer];
|
|
(*surface)->AddRef();
|
|
return;
|
|
}
|
|
void WINAPI D3DDevice_GetRenderTarget(
|
|
D3DSurface **surface)
|
|
{
|
|
*surface = g_pDevice->m_pRenderTarget;
|
|
if (*surface) { (*surface)->AddRef(); }
|
|
return;
|
|
}
|
|
HRESULT WINAPI D3DDevice_GetDepthStencilSurface(
|
|
D3DSurface **surface)
|
|
{
|
|
*surface = g_pDevice->m_pZBuffer;
|
|
if (*surface)
|
|
{
|
|
(*surface)->AddRef();
|
|
return S_OK;
|
|
}
|
|
return D3DERR_NOTFOUND;
|
|
}
|
|
void WINAPI D3DDevice_GetTexture(
|
|
DWORD Stage,
|
|
D3DBaseTexture **texture)
|
|
{
|
|
CDevice *device = g_pDevice;
|
|
D3DBaseTexture **textures = device->m_Textures;
|
|
if (textures[Stage]) { textures[Stage]->AddRef(); }
|
|
*texture = textures[Stage];
|
|
return;
|
|
}
|
|
void WINAPI D3DDevice_GetPalette(
|
|
DWORD Stage,
|
|
D3DPalette **palette)
|
|
{
|
|
CDevice *device = g_pDevice;
|
|
D3DPalette **palettes = device->m_Palettes;
|
|
if (palettes[Stage]) { palettes[Stage]->AddRef(); }
|
|
*palette = palettes[Stage];
|
|
return;
|
|
}
|
|
void WINAPI D3DDevice_SetPalette(
|
|
DWORD Stage,
|
|
D3DPalette *palette)
|
|
{
|
|
CDevice *device = g_pDevice;
|
|
if (device->m_Palettes[Stage])
|
|
{
|
|
device->RecordResourceReadPush(device->m_Palettes[Stage]);
|
|
InternalRelease(device->m_Palettes[Stage]);
|
|
}
|
|
device->m_Palettes[Stage] = palette;
|
|
if (palette)
|
|
{
|
|
InternalAddRef(palette);
|
|
DWORD size = palette->Common >> 28;
|
|
DWORD *push = device->StartPush();
|
|
Push1(push, 0x1b20 + Stage * 64, palette->Data | size);
|
|
device->EndPush(push + 2);
|
|
}
|
|
return;
|
|
}
|
|
void WINAPI D3DDevice_SetIndices(
|
|
D3DIndexBuffer *buffer,
|
|
UINT base)
|
|
{
|
|
CDevice *device = g_pDevice;
|
|
if (buffer)
|
|
{
|
|
InternalAddRef(buffer);
|
|
D3D__IndexData = (WORD *)buffer->Data;
|
|
}
|
|
else { D3D__IndexData = NULL; }
|
|
if (device->m_pIndexBuffer) { InternalRelease(device->m_pIndexBuffer); }
|
|
device->m_pIndexBuffer = buffer;
|
|
device->m_IndexBase = base;
|
|
return;
|
|
}
|
|
void WINAPI D3DDevice_GetIndices(
|
|
D3DIndexBuffer **buffer,
|
|
UINT *base)
|
|
{
|
|
CDevice *device = g_pDevice;
|
|
D3DIndexBuffer *current = device->m_pIndexBuffer;
|
|
if (current)
|
|
{
|
|
current->AddRef();
|
|
*buffer = current;
|
|
*base = device->m_IndexBase;
|
|
}
|
|
else
|
|
{
|
|
*buffer = NULL;
|
|
*base = 0;
|
|
}
|
|
return;
|
|
}
|
|
void WINAPI D3DDevice_Nop(
|
|
void)
|
|
{
|
|
CDevice *device = g_pDevice;
|
|
DWORD *push = device->StartPush();
|
|
Push1(push, NV097_NO_OPERATION, 0);
|
|
device->EndPush(push + 2);
|
|
return;
|
|
}
|
|
void WINAPI D3DDevice_FlushVertexCache(
|
|
void)
|
|
{
|
|
CDevice *device = g_pDevice;
|
|
DWORD *push = device->StartPush();
|
|
Push1(push, 0x1710, 0);
|
|
device->EndPush(push + 2);
|
|
return;
|
|
}
|
|
|
|
void WINAPI D3DDevice_SetViewport(
|
|
const D3DVIEWPORT8 *pViewport)
|
|
{
|
|
D3DSurface *pSurface;
|
|
CDevice *pDevice = g_pDevice;
|
|
if (pDevice->m_pRenderTarget == &pDevice->m_FrameBufferSurfaces[0])
|
|
{
|
|
pSurface = &pDevice->m_FrameBufferSurfaces[1];
|
|
}
|
|
else { pSurface = pDevice->m_pRenderTarget; }
|
|
DWORD left = max(pViewport->X, 0);
|
|
DWORD top = max(pViewport->Y, 0);
|
|
DWORD right = min(pViewport->X + pViewport->Width, (INT)PixelJar::GetWidth(pSurface));
|
|
DWORD bottom = min(pViewport->Y + pViewport->Height, (INT)PixelJar::GetHeight(pSurface));
|
|
pDevice->m_Viewport.X = left;
|
|
pDevice->m_Viewport.Y = top;
|
|
pDevice->m_Viewport.Width = right - left;
|
|
pDevice->m_Viewport.Height = bottom - top;
|
|
pDevice->m_Viewport.MinZ = pViewport->MinZ;
|
|
pDevice->m_Viewport.MaxZ = pViewport->MaxZ;
|
|
UpdateProjectionViewportTransform();
|
|
D3DDevice_SetScissors(0, 0, NULL);
|
|
DWORD *push = pDevice->StartPush();
|
|
push = CommonSetViewport(pDevice, push);
|
|
pDevice->EndPush(push);
|
|
pDevice->m_DirtyFlags |= 1;
|
|
return;
|
|
}
|
|
void WINAPI D3DDevice_SetTexture(
|
|
DWORD stage,
|
|
D3DBaseTexture *texture)
|
|
{
|
|
DWORD *push;
|
|
CDevice *device = g_pDevice;
|
|
D3DBaseTexture *previous = device->m_Textures[stage];
|
|
if (previous)
|
|
{
|
|
device->RecordResourceReadPush(previous);
|
|
InternalRelease(previous);
|
|
}
|
|
device->m_Textures[stage] = texture;
|
|
if (!texture)
|
|
{
|
|
push = device->StartPush();
|
|
Push1(push, 0x1b0c + stage * 64, 0);
|
|
device->EndPush(push + 2);
|
|
device->m_TextureCubemapAndDimension[stage] = ~0UL;
|
|
device->m_DirtyFlags |= 0x408;
|
|
}
|
|
else
|
|
{
|
|
InternalAddRef(texture);
|
|
push = device->StartPush();
|
|
Push2(push, 0x1b00 + stage * 64, texture->Data, texture->Format);
|
|
push += 3;
|
|
if (texture->Size != 0)
|
|
{
|
|
DWORD width = (texture->Size & D3DSIZE_WIDTH_MASK) + 1;
|
|
DWORD height = ((texture->Size & D3DSIZE_HEIGHT_MASK) >> D3DSIZE_HEIGHT_SHIFT) + 1;
|
|
DWORD pitch = PixelJar::GetPitch(texture);
|
|
Push1(push, 0x1b10 + stage * 64, pitch << 16);
|
|
Push1(push + 2, 0x1b1c + stage * 64, (width << 16) | height);
|
|
push += 4;
|
|
}
|
|
DWORD dimensions = texture->Format & (D3DFORMAT_CUBEMAP | D3DFORMAT_DIMENSION_MASK);
|
|
if (device->m_TextureCubemapAndDimension[stage] != dimensions)
|
|
{
|
|
device->m_TextureCubemapAndDimension[stage] = dimensions;
|
|
/* January always reprograms CONTROL0 when these format bits change. */
|
|
Push1(push, 0x1b0c + stage * 64, device->m_TextureControl0Enabled[stage]);
|
|
push += 2;
|
|
device->m_DirtyFlags |= 0x400;
|
|
if (!previous) device->m_DirtyFlags |= 8;
|
|
}
|
|
device->EndPush(push);
|
|
}
|
|
return;
|
|
}
|
|
/* BUG (original): batches advance caller-supplied rectangle/point pointers by
|
|
* 16 even when the final batch is shorter. Strict C pointer bounds therefore
|
|
* require caller backing arrays rounded up to a 16-entry batch. The binary
|
|
* proves the fixed increment; a corrected build would advance by batch.
|
|
* Swizzled copies additionally require writable rectangle storage, as noted
|
|
* at the actual original store below. Neither behavior is introduced to steer
|
|
* the compiler. Normal matching tests do not establish arbitrary-input safety.
|
|
*/
|
|
void WINAPI D3DDevice_CopyRects(
|
|
D3DSurface *sourceSurface,
|
|
const RECT *sourceRects,
|
|
UINT count,
|
|
D3DSurface *destinationSurface,
|
|
const POINT *destinationPoints)
|
|
{
|
|
const DWORD maxRectangles = 16;
|
|
RECT rectangles[maxRectangles];
|
|
POINT points[maxRectangles];
|
|
DWORD swizzledColumns, swizzledRows;
|
|
DWORD bytesPerPixel = PixelJar::GetBitsPerPixel(sourceSurface) / 8;
|
|
DWORD sourcePitch = PixelJar::GetPitch(sourceSurface);
|
|
DWORD destinationPitch = PixelJar::GetPitch(destinationSurface);
|
|
BOOL swizzled = PixelJar::IsSwizzled(sourceSurface) || PixelJar::IsCompressed(sourceSurface);
|
|
CDevice *device = g_pDevice;
|
|
if (count == 0) count = 1;
|
|
if (swizzled)
|
|
{
|
|
DWORD slice = PixelJar::GetSlice(sourceSurface);
|
|
bytesPerPixel = 1;
|
|
if (slice <= 8128)
|
|
{
|
|
sourcePitch = (slice + 63) & ~63;
|
|
destinationPitch = sourcePitch;
|
|
swizzledColumns = slice;
|
|
swizzledRows = 1;
|
|
}
|
|
else
|
|
{
|
|
sourcePitch = 4096;
|
|
destinationPitch = 4096;
|
|
swizzledColumns = 4096;
|
|
swizzledRows = slice / 4096;
|
|
}
|
|
}
|
|
do
|
|
{
|
|
RECT *rects;
|
|
POINT *destinations;
|
|
DWORD batch = min(maxRectangles, count);
|
|
count -= batch;
|
|
if (sourceRects)
|
|
{
|
|
rects = (RECT *)sourceRects;
|
|
sourceRects += maxRectangles;
|
|
}
|
|
else
|
|
{
|
|
rects = rectangles;
|
|
for (DWORD i = 0; i < batch; i++)
|
|
{
|
|
rectangles[i].top = 0;
|
|
rectangles[i].bottom = PixelJar::GetHeight(sourceSurface);
|
|
rectangles[i].left = 0;
|
|
rectangles[i].right = PixelJar::GetWidth(sourceSurface);
|
|
}
|
|
}
|
|
if (destinationPoints)
|
|
{
|
|
destinations = (POINT *)destinationPoints;
|
|
destinationPoints += maxRectangles;
|
|
}
|
|
else
|
|
{
|
|
destinations = points;
|
|
for (DWORD i = 0; i < batch; i++)
|
|
{
|
|
points[i].x = rects[i].left;
|
|
points[i].y = rects[i].top;
|
|
}
|
|
}
|
|
if (swizzled)
|
|
{
|
|
/* BUG (original): the target writes through the const-qualified
|
|
* input rectangle pointer. This matching entry requires mutable
|
|
* backing storage when explicit swizzled rectangles are supplied.
|
|
* A corrected build would use a local rectangle copy. */
|
|
for (DWORD i = 0; i < batch; i++)
|
|
{
|
|
rects[i].left = 0;
|
|
rects[i].top = 0;
|
|
rects[i].right = swizzledColumns;
|
|
rects[i].bottom = swizzledRows;
|
|
}
|
|
}
|
|
GPUCopyVideoRectangle(bytesPerPixel, sourceSurface->Data, sourcePitch,
|
|
destinationSurface->Data, destinationPitch, batch, rects, destinations);
|
|
} while (count);
|
|
device->RecordSurfaceWritePush(sourceSurface);
|
|
device->RecordSurfaceWritePush(destinationSurface);
|
|
return;
|
|
}
|
|
void WINAPI D3DDevice_SetScissors(
|
|
DWORD count,
|
|
BOOL exclusive,
|
|
const D3DRECT *rects)
|
|
{
|
|
const D3DRECT *current;
|
|
D3DRECT viewport;
|
|
DWORD i;
|
|
CDevice *device = g_pDevice;
|
|
if (count == 0)
|
|
{
|
|
viewport.x1 = device->m_Viewport.X;
|
|
viewport.y1 = device->m_Viewport.Y;
|
|
viewport.x2 = viewport.x1 + device->m_Viewport.Width;
|
|
viewport.y2 = viewport.y1 + device->m_Viewport.Height;
|
|
exclusive = FALSE;
|
|
rects = &viewport;
|
|
count = 1;
|
|
}
|
|
DWORD *push = device->StartPush();
|
|
Push1(push, 0x2b4, exclusive);
|
|
push += 2;
|
|
float xScale = device->m_SuperSampleScaleX;
|
|
float yScale = device->m_SuperSampleScaleY;
|
|
for (current = rects, i = 0; i < count; i++, current++)
|
|
{
|
|
Push1(push, 0x2c0 + i * 4,
|
|
Round(xScale * current->x1) | ((Round(xScale * current->x2) - 1) << 16));
|
|
Push1(push + 2, 0x2e0 + i * 4,
|
|
Round(yScale * current->y1) | ((Round(yScale * current->y2) - 1) << 16));
|
|
push += 4;
|
|
}
|
|
device->EndPush(push);
|
|
memcpy(&device->m_ScissorsRects[0], rects, count * sizeof(D3DRECT));
|
|
device->m_ScissorsCount = count;
|
|
device->m_ScissorsExclusive = exclusive;
|
|
return;
|
|
}
|
|
|
|
BYTE *WINAPI D3D::GetVisibilityAddress(
|
|
DWORD index)
|
|
{
|
|
CDevice *device = g_pDevice;
|
|
DWORD page = index >> 8;
|
|
if (device->m_ReportAllocations[page] == NULL)
|
|
{
|
|
device->m_ReportAllocations[page] = MmAllocateContiguousMemoryEx(
|
|
4096, 0, 0x00ffffff, 0, PAGE_READWRITE);
|
|
if (device->m_ReportAllocations[page] == NULL)
|
|
return NULL;
|
|
}
|
|
VisibilityReport *report = (VisibilityReport *)
|
|
((BYTE *)device->m_ReportAllocations[page] + (index & 255) * 16);
|
|
if (!(device->m_StateFlags & 4))
|
|
report->Status = 0xffffffff;
|
|
return (BYTE *)report;
|
|
}
|
|
void WINAPI D3DDevice_BeginVisibilityTest(
|
|
void)
|
|
{
|
|
CDevice *device = g_pDevice;
|
|
DWORD *push = device->StartPush();
|
|
Push2(push, 0x17c8, 1, 1);
|
|
device->EndPush(push + 3);
|
|
return;
|
|
}
|
|
HRESULT WINAPI D3DDevice_EndVisibilityTest(
|
|
DWORD index)
|
|
{
|
|
BYTE *address = GetVisibilityAddress(index);
|
|
if (address == NULL)
|
|
return E_OUTOFMEMORY;
|
|
CDevice *device = g_pDevice;
|
|
DWORD *push = device->StartPush();
|
|
Push2(push, 0x17cc, 0, ((DWORD)address & 0x02ffffff) | 0x01000000);
|
|
device->EndPush(push + 3);
|
|
device->KickOff();
|
|
return S_OK;
|
|
}
|
|
HRESULT WINAPI D3DDevice_GetVisibilityTestResult(
|
|
DWORD index,
|
|
UINT *result,
|
|
ULONGLONG *timeStamp)
|
|
{
|
|
CDevice *device = g_pDevice;
|
|
VisibilityReport *report = (VisibilityReport *)
|
|
((BYTE *)device->m_ReportAllocations[index >> 8] + (index & 255) * 16);
|
|
if (report->Status == 0xffffffff)
|
|
return D3DERR_TESTINCOMPLETE;
|
|
*result = report->Samples;
|
|
if (timeStamp)
|
|
*timeStamp = report->TimeStamp;
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT WINAPI D3DDevice_Reset(
|
|
D3DPRESENT_PARAMETERS *parameters)
|
|
{
|
|
CDevice *device = g_pDevice;
|
|
KickOffAndWaitForIdle();
|
|
while (device->m_Miniport.IsFlipPending())
|
|
{
|
|
/* The original API waits for the final queued display flip. */
|
|
}
|
|
device->FreeFrameBuffers();
|
|
HRESULT result = device->InitializeFrameBuffers(parameters);
|
|
if (FAILED(result))
|
|
{
|
|
device->FreeFrameBuffers();
|
|
return result;
|
|
}
|
|
device->m_Miniport.SetVideoMode(parameters->BackBufferWidth,
|
|
parameters->BackBufferHeight, parameters->FullScreen_RefreshRateInHz,
|
|
parameters->Flags, parameters->BackBufferFormat,
|
|
parameters->FullScreen_PresentationInterval,
|
|
PixelJar::GetPitch(&device->m_FrameBufferSurfaces[1]));
|
|
D3DDevice_SetRenderTarget(&device->m_FrameBufferSurfaces[0],
|
|
device->m_pAutoDepthBuffer ? &device->m_AutoDepthSurface : NULL);
|
|
D3DDevice_Clear(0, NULL, D3DCLEAR_STENCIL | D3DCLEAR_ZBUFFER, 0, 1.0f, 0);
|
|
return S_OK;
|
|
}
|
|
|
|
void WINAPI D3DDevice_SetRenderTarget(
|
|
D3DSurface *renderTarget,
|
|
D3DSurface *zBuffer)
|
|
{
|
|
CDevice *device = g_pDevice;
|
|
if (renderTarget == NULL)
|
|
renderTarget = device->m_pRenderTarget;
|
|
DWORD width = PixelJar::GetWidth(renderTarget);
|
|
DWORD height = PixelJar::GetHeight(renderTarget);
|
|
DWORD renderPitch = PixelJar::GetPitch(renderTarget);
|
|
if (renderTarget == &device->m_FrameBufferSurfaces[0])
|
|
{
|
|
DWORD sampling = D3D__RenderState[D3DRS_MULTISAMPLETYPE];
|
|
if ((sampling & 0x3000) && (sampling & 0x1000))
|
|
{
|
|
width >>= 1;
|
|
if ((sampling & 15) > 1)
|
|
height >>= 1;
|
|
}
|
|
}
|
|
DWORD depthPitch = zBuffer ? PixelJar::GetPitch(zBuffer) : renderPitch;
|
|
InternalAddRef(renderTarget);
|
|
if (device->m_pRenderTarget)
|
|
{
|
|
device->RecordSurfaceWritePush(device->m_pRenderTarget);
|
|
InternalReleaseSurface(device->m_pRenderTarget);
|
|
}
|
|
device->m_pRenderTarget = renderTarget;
|
|
if (device->m_pZBuffer)
|
|
{
|
|
device->RecordSurfaceWritePush(device->m_pZBuffer);
|
|
InternalReleaseSurface(device->m_pZBuffer);
|
|
}
|
|
device->m_pZBuffer = zBuffer;
|
|
if (zBuffer)
|
|
{
|
|
InternalAddRef(zBuffer);
|
|
PixelJar::GetDepthBufferScale(zBuffer, &device->m_ZScale);
|
|
}
|
|
DWORD *push = device->StartPush();
|
|
DWORD renderOffset = renderTarget->Data;
|
|
DWORD depthOffset = zBuffer ? zBuffer->Data : 0;
|
|
DWORD pitch = (renderPitch & 0xffff) | (depthPitch << 16);
|
|
/* Target-evidenced NV2A surface switch synchronization: each register
|
|
* update is bracketed by NOP and idle methods, and the sequence is repeated
|
|
* twice. These are hardware command words, not native instruction data. */
|
|
for (DWORD i = 0; i < 2; i++)
|
|
{
|
|
Push1(push, NV097_NO_OPERATION, 0);
|
|
Push1(push + 2, 0x20c, pitch);
|
|
Push1(push + 4, NV097_NO_OPERATION, 0);
|
|
Push1(push + 6, NV097_WAIT_FOR_IDLE, 0);
|
|
push += 8;
|
|
Push1(push, NV097_NO_OPERATION, 0);
|
|
Push1(push + 2, 0x210, renderOffset);
|
|
Push1(push + 4, NV097_NO_OPERATION, 0);
|
|
Push1(push + 6, NV097_WAIT_FOR_IDLE, 0);
|
|
push += 8;
|
|
Push1(push, NV097_NO_OPERATION, 0);
|
|
Push1(push + 2, 0x214, depthOffset);
|
|
Push1(push + 4, NV097_NO_OPERATION, 0);
|
|
Push1(push + 6, NV097_WAIT_FOR_IDLE, 0);
|
|
push += 8;
|
|
}
|
|
Push2(push, 0x200, width << 16, height << 16);
|
|
push = CommonSetControl0(device, push + 3);
|
|
Push1(push, 0x30c, D3D__RenderState[D3DRS_ZENABLE] && device->m_pZBuffer);
|
|
Push1(push + 2, 0x32c, D3D__RenderState[D3DRS_STENCILENABLE] && device->m_pZBuffer);
|
|
push += 4;
|
|
if ((device->m_StateFlags & 0x100) && renderTarget == &device->m_FrameBufferSurfaces[0])
|
|
{
|
|
device->m_StateFlags &= ~0x100;
|
|
Push1(push, 0x130, 0);
|
|
push += 2;
|
|
}
|
|
device->EndPush(push);
|
|
CommonSetSurfaceFormat(device);
|
|
CommonSetPassthroughProgram(device);
|
|
D3DVIEWPORT8 viewport;
|
|
viewport.X = 0;
|
|
viewport.Y = 0;
|
|
viewport.Width = width;
|
|
viewport.Height = height;
|
|
viewport.MinZ = 0.0f;
|
|
viewport.MaxZ = 1.0f;
|
|
D3DDevice_SetViewport(&viewport);
|
|
D3DDevice_SetRenderStateNotInline(D3DRS_DXT1NOISEENABLE,
|
|
D3D__RenderState[D3DRS_DXT1NOISEENABLE]);
|
|
return;
|
|
}
|
|
HRESULT WINAPI D3DDevice_GetVertexBlendModelView(
|
|
UINT count,
|
|
D3DMATRIX *modelViews,
|
|
D3DMATRIX *projectionViewport)
|
|
{
|
|
CDevice *device = g_pDevice;
|
|
if (modelViews)
|
|
memcpy(modelViews, device->m_ModelViewTransform, count * sizeof(D3DMATRIX));
|
|
if (projectionViewport)
|
|
*projectionViewport = device->m_ProjectionViewport;
|
|
return (device->m_DirtyFlags & 0x80000000) ? S_OK : S_FALSE;
|
|
}
|
|
void WINAPI D3DDevice_SetModelView(
|
|
const D3DMATRIX *modelView,
|
|
const D3DMATRIX *inverseModelView,
|
|
const D3DMATRIX *composite)
|
|
{
|
|
CDevice *device = g_pDevice;
|
|
if (composite == NULL)
|
|
{
|
|
device->m_DirtyFlags &= ~0x80000000;
|
|
device->m_DirtyFlags |= 2;
|
|
return;
|
|
}
|
|
device->m_DirtyFlags &= ~2;
|
|
device->m_DirtyFlags |= 0x80000000;
|
|
DWORD *push = device->StartPush();
|
|
DumpMatrixTransposed(push, 0x400480, modelView);
|
|
DumpMatrixTransposed(push + 17, 0x400680, composite);
|
|
push += 34;
|
|
if (inverseModelView)
|
|
{
|
|
PushCount(push, 0x580, 12);
|
|
memcpy(push + 1, inverseModelView, 12 * sizeof(float));
|
|
push += 13;
|
|
}
|
|
device->EndPush(push);
|
|
if (!(device->m_StateFlags & 0x10))
|
|
device->m_ModelViewTransform[0] = *modelView;
|
|
return;
|
|
}
|
|
|
|
/* Display controls assume an initialized device; field sampling is actual GPIO
|
|
* I/O and register reads below are genuine volatile MMIO, not byte steering. */
|
|
void WINAPI D3DDevice_BlockUntilVerticalBlank(
|
|
void)
|
|
{
|
|
CDevice *device = g_pDevice;
|
|
KeClearEvent(&device->m_Miniport.m_VerticalBlankEvent);
|
|
KeWaitForSingleObject(&device->m_Miniport.m_VerticalBlankEvent,
|
|
UserRequest, UserMode, FALSE, NULL);
|
|
return;
|
|
}
|
|
void WINAPI D3DDevice_SetFlickerFilter(
|
|
DWORD filter)
|
|
{
|
|
AvSendTVEncoderOption(g_pDevice->m_Miniport.m_RegisterBase,
|
|
AV_OPTION_FLICKER_FILTER, filter, NULL);
|
|
return;
|
|
}
|
|
void WINAPI D3DDevice_SetSoftDisplayFilter(
|
|
BOOL enable)
|
|
{
|
|
AvSendTVEncoderOption(g_pDevice->m_Miniport.m_RegisterBase,
|
|
AV_OPTION_SOFT_DISPLAY_FILTER, enable, NULL);
|
|
return;
|
|
}
|
|
void WINAPI D3DDevice_GetRasterStatus(
|
|
D3DRASTER_STATUS *status)
|
|
{
|
|
CDevice *device = g_pDevice;
|
|
DWORD line = REG_RD32(device->m_NvBase, NV2A_RASTER_POSITION)
|
|
& NV2A_RASTER_POSITION_MASK;
|
|
if (line != 0 && line < device->m_DisplayHeight)
|
|
{
|
|
status->InVBlank = FALSE;
|
|
status->ScanLine = line;
|
|
}
|
|
else
|
|
{
|
|
status->InVBlank = TRUE;
|
|
status->ScanLine = 0;
|
|
}
|
|
return;
|
|
}
|
|
BOOL WINAPI D3DDevice_IsBusy(
|
|
void)
|
|
{
|
|
CDevice *device = g_pDevice;
|
|
_HWREG *registerBase = device->m_NvBase;
|
|
return (((DWORD)device->HwGet() & 0x0fffffff) !=
|
|
((DWORD)device->m_pKickOff & 0x0fffffff)) ||
|
|
REG_RD32(registerBase, NV2A_GRAPHICS_STATUS) != 0;
|
|
}
|
|
void WINAPI D3DDevice_GetDisplayFieldStatus(
|
|
D3DFIELD_STATUS *status)
|
|
{
|
|
CDevice *device = g_pDevice;
|
|
status->VBlankCount = device->m_Miniport.m_VBlankCount;
|
|
if (device->m_Miniport.m_CurrentAvInfo &
|
|
(AV_FLAGS_INTERLACED | AV_FLAGS_FIELD))
|
|
{
|
|
status->Field = (BYTE)device->m_Miniport.IsOddField() ? D3DFIELD_ODD : D3DFIELD_EVEN;
|
|
}
|
|
else
|
|
{
|
|
status->Field = D3DFIELD_PROGRESSIVE;
|
|
}
|
|
return;
|
|
}
|
|
void WINAPI D3DDevice_SetTile(
|
|
DWORD index,
|
|
D3DTILE *tileInfo)
|
|
{
|
|
CDevice *device = g_pDevice;
|
|
D3DTILE tile;
|
|
if (tileInfo != NULL && tileInfo->pMemory != NULL)
|
|
{
|
|
tile = *tileInfo;
|
|
if (!(tile.Flags & D3DTILE_FLAGS_ZCOMPRESS))
|
|
{
|
|
tile.ZOffset = 0;
|
|
tile.ZStartTag = 0;
|
|
}
|
|
device->m_Tile[index] = tile;
|
|
device->m_Miniport.CreateTile(index, (DWORD)tile.pMemory & 0x03ffffff,
|
|
tile.Size, tile.Pitch, tile.Flags, tile.ZStartTag, tile.ZOffset);
|
|
}
|
|
else
|
|
{
|
|
device->m_Miniport.DestroyTile(index, device->m_Tile[index].ZOffset);
|
|
memset(&device->m_Tile[index], 0, sizeof(D3DTILE));
|
|
}
|
|
return;
|
|
}
|
|
/* Preserves the original partial-bank iteration: i is compared with the batch
|
|
* count, not start+count. These APIs assume a valid tag partition/range and an
|
|
* idle GPU. Nonzero starting indices can transfer fewer words than requested;
|
|
* changing that historical quirk intentionally changes the target bytes. */
|
|
void WINAPI D3DDevice_SetTileCompressionTagBits(
|
|
DWORD partition,
|
|
DWORD address,
|
|
DWORD *data,
|
|
DWORD count)
|
|
{
|
|
_HWREG *registerBase = g_pDevice->m_NvBase;
|
|
DWORD dataAddress = address % 16;
|
|
address /= 16;
|
|
while (count)
|
|
{
|
|
REG_WR32(registerBase, NV2A_TAG_INDEX,
|
|
(((NV2A_TAG_PARTITION_SELECT + partition) & NV2A_TAG_SELECT_MASK) << 16)
|
|
| ((address++ & NV2A_TAG_ADDRESS_MASK) << 6));
|
|
DWORD dwordCount = min(count, 16 - dataAddress);
|
|
count -= dwordCount;
|
|
for (DWORD i = dataAddress; i < dwordCount; i++)
|
|
{
|
|
REG_WR32(registerBase, NV2A_TAG_DATA + i * sizeof(DWORD), *data++);
|
|
}
|
|
dataAddress = 0;
|
|
}
|
|
return;
|
|
}
|
|
void WINAPI D3DDevice_GetTileCompressionTagBits(
|
|
DWORD partition,
|
|
DWORD address,
|
|
DWORD *data,
|
|
DWORD count)
|
|
{
|
|
_HWREG *registerBase = g_pDevice->m_NvBase;
|
|
DWORD dataAddress = address % 16;
|
|
address /= 16;
|
|
while (count)
|
|
{
|
|
REG_WR32(registerBase, NV2A_TAG_INDEX,
|
|
(((NV2A_TAG_PARTITION_SELECT + partition) & NV2A_TAG_SELECT_MASK) << 16)
|
|
| ((address++ & NV2A_TAG_ADDRESS_MASK) << 6));
|
|
DWORD dwordCount = min(count, 16 - dataAddress);
|
|
count -= dwordCount;
|
|
for (DWORD i = dataAddress; i < dwordCount; i++)
|
|
{
|
|
*data++ = REG_RD32(registerBase, NV2A_TAG_DATA + i * sizeof(DWORD));
|
|
}
|
|
dataAddress = 0;
|
|
}
|
|
return;
|
|
}
|
|
|
|
/* As with GetTileCompressionTagBits, the original first partial-bank bound is
|
|
* retained. ZStartTag/ZEndTag must describe a valid aligned hardware-tag range. */
|
|
DWORD WINAPI D3DDevice_GetTileCompressionTags(
|
|
DWORD startTag,
|
|
DWORD endTag)
|
|
{
|
|
KickOffAndWaitForIdle();
|
|
_HWREG *registerBase = g_pDevice->m_NvBase;
|
|
DWORD compressedTags = 0;
|
|
DWORD dwordsPerPartition = (endTag - startTag) / (4 * 32);
|
|
DWORD partitionAddressStart = startTag / (4 * 32);
|
|
for (DWORD partition = 0; partition < 4; partition++)
|
|
{
|
|
DWORD dwordsToRead = dwordsPerPartition;
|
|
DWORD dataStart = partitionAddressStart % 16;
|
|
for (DWORD addressOffset = 0; dwordsToRead; addressOffset++)
|
|
{
|
|
REG_WR32(registerBase, NV2A_TAG_INDEX,
|
|
(((NV2A_TAG_PARTITION_SELECT + partition) & NV2A_TAG_SELECT_MASK) << 16)
|
|
| (((partitionAddressStart / 16 + addressOffset) & NV2A_TAG_ADDRESS_MASK) << 6));
|
|
DWORD dwordCount = min(dwordsToRead, 16 - dataStart);
|
|
dwordsToRead -= dwordCount;
|
|
for (DWORD i = dataStart; i < dwordCount; i++)
|
|
{
|
|
DWORD data = REG_RD32(registerBase,
|
|
NV2A_TAG_DATA + i * sizeof(DWORD));
|
|
while (data)
|
|
{
|
|
compressedTags++;
|
|
data &= data - 1;
|
|
}
|
|
}
|
|
dataStart = 0;
|
|
}
|
|
}
|
|
return compressedTags;
|
|
}
|
|
|
|
/* The source must contain the destination mip chain. Compressed logarithmic
|
|
* dimensions stop at their minimum block size; faces occupy 128-byte strides. */
|
|
void WINAPI D3DDevice_UpdateTexture(
|
|
D3DBaseTexture *source,
|
|
D3DBaseTexture *destination)
|
|
{
|
|
DWORD sourceMips = PixelJar::GetMipmapLevelCount(source);
|
|
DWORD size;
|
|
DWORD sourceSize;
|
|
DWORD sourceOffset = 0;
|
|
if (sourceMips == 1)
|
|
{
|
|
DWORD depth = PixelJar::GetDepth(source);
|
|
size = PixelJar::GetSlice(destination) * depth;
|
|
sourceSize = size;
|
|
}
|
|
else
|
|
{
|
|
DWORD texelSize = PixelJar::GetBitsPerPixel(source);
|
|
DWORD logMin = MinimumTextureSizeOfD3DFORMAT(PixelJar::GetFormat(source));
|
|
size = 0;
|
|
DWORD destinationWidth = PixelJar::GetLogWidth(destination);
|
|
DWORD destinationHeight = PixelJar::GetLogHeight(destination);
|
|
DWORD destinationDepth = PixelJar::GetLogDepth(destination);
|
|
DWORD sourceWidth = PixelJar::GetLogWidth(source);
|
|
DWORD sourceHeight = PixelJar::GetLogHeight(source);
|
|
DWORD sourceDepth = PixelJar::GetLogDepth(source);
|
|
DWORD currentWidth = destinationWidth;
|
|
DWORD currentHeight = destinationHeight;
|
|
DWORD currentDepth = destinationDepth;
|
|
for (DWORD i = PixelJar::GetMipmapLevelCount(destination); i != 0; i--)
|
|
{
|
|
size += (1UL << (currentWidth + currentHeight + currentDepth)) * texelSize / 8;
|
|
if (currentWidth > logMin) currentWidth--;
|
|
if (currentHeight > logMin) currentHeight--;
|
|
if (currentDepth > logMin) currentDepth--;
|
|
}
|
|
sourceSize = 0;
|
|
currentWidth = sourceWidth;
|
|
currentHeight = sourceHeight;
|
|
currentDepth = sourceDepth;
|
|
for (DWORD i = sourceMips; i != 0; i--)
|
|
{
|
|
if (currentWidth == destinationWidth && currentHeight == destinationHeight &&
|
|
currentDepth == destinationDepth)
|
|
{
|
|
sourceOffset = sourceSize;
|
|
}
|
|
sourceSize += (1UL << (currentWidth + currentHeight + currentDepth)) * texelSize / 8;
|
|
if (currentWidth > logMin) currentWidth--;
|
|
if (currentHeight > logMin) currentHeight--;
|
|
if (currentDepth > logMin) currentDepth--;
|
|
}
|
|
}
|
|
if (source->Format & D3DFORMAT_CUBEMAP)
|
|
{
|
|
DWORD sourceStride = (sourceSize + 127) & ~127UL;
|
|
DWORD destinationStride = (size + 127) & ~127UL;
|
|
for (DWORD i = 0; i < 6; i++)
|
|
{
|
|
DWORD sourceData = source->Data + i * sourceStride;
|
|
DWORD destinationData = destination->Data + i * destinationStride;
|
|
GPUCopyMemory(sourceData + sourceOffset, destinationData, size);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DWORD sourceData = source->Data;
|
|
DWORD destinationData = destination->Data;
|
|
GPUCopyMemory(sourceData + sourceOffset, destinationData, size);
|
|
}
|
|
return;
|
|
}
|
|
HRESULT WINAPI D3DDevice_LightEnable(
|
|
DWORD index,
|
|
BOOL enable)
|
|
{
|
|
CDevice *device = g_pDevice;
|
|
if (index >= device->m_LightCount || !(device->m_pLights[index].Flags & 1))
|
|
{
|
|
D3DLIGHT8 light;
|
|
memset(&light, 0, sizeof(light));
|
|
light.Type = D3DLIGHT_DIRECTIONAL;
|
|
light.Direction.z = 1.0f;
|
|
light.Diffuse.r = 1.0f;
|
|
light.Diffuse.g = 1.0f;
|
|
light.Diffuse.b = 1.0f;
|
|
HRESULT result = D3DDevice_SetLight(index, &light);
|
|
if (result != S_OK) return result;
|
|
}
|
|
Light *light = &device->m_pLights[index];
|
|
light->Flags |= 4;
|
|
/* A real link pointer replaces the historical fabricated previous Light
|
|
* object before m_pActiveLights. No before-object typed member access. */
|
|
Light **link = &device->m_pActiveLights;
|
|
while (*link != NULL)
|
|
{
|
|
if (*link == light)
|
|
{
|
|
*link = light->pNext;
|
|
break;
|
|
}
|
|
link = &(*link)->pNext;
|
|
}
|
|
if (enable)
|
|
{
|
|
light->pNext = device->m_pActiveLights;
|
|
device->m_pActiveLights = light;
|
|
}
|
|
device->m_DirtyFlags |= 0x20;
|
|
return S_OK;
|
|
}
|
|
void WINAPI D3DDevice_SetVertexBlendModelView(
|
|
UINT count,
|
|
const D3DMATRIX *modelViews,
|
|
const D3DMATRIX *inverseModelViews,
|
|
const D3DMATRIX *projectionViewport)
|
|
{
|
|
CDevice *device = g_pDevice;
|
|
if (modelViews == NULL)
|
|
{
|
|
device->m_DirtyFlags &= ~0x80000000UL;
|
|
device->m_DirtyFlags |= 2;
|
|
return;
|
|
}
|
|
device->m_DirtyFlags &= ~2UL;
|
|
device->m_DirtyFlags |= 0x80000000UL;
|
|
DWORD *push = device->StartPush(count * 34 + 17);
|
|
for (UINT i = 0; i < count; i++)
|
|
{
|
|
DumpMatrixTransposed(push, 0x400480 + i * 0x40, &modelViews[i]);
|
|
push += 17;
|
|
}
|
|
if (inverseModelViews != NULL)
|
|
{
|
|
for (UINT i = 0; i < count; i++)
|
|
{
|
|
push[0] = 0x300580 + i * 0x40;
|
|
memcpy(push + 1, &inverseModelViews[i], 12 * sizeof(DWORD));
|
|
push += 13;
|
|
}
|
|
}
|
|
DumpMatrixTransposed(push, 0x400680, projectionViewport);
|
|
device->EndPush(push + 17);
|
|
if (!(device->m_StateFlags & 0x10))
|
|
{
|
|
memcpy(device->m_ModelViewTransform, modelViews, count * sizeof(D3DMATRIX));
|
|
device->m_ProjectionViewport = *projectionViewport;
|
|
}
|
|
return;
|
|
}
|
|
HRESULT WINAPI D3DDevice_PersistDisplay(
|
|
void)
|
|
{
|
|
CDevice *device = g_pDevice;
|
|
D3DSurface *copy = (D3DSurface *)AvGetSavedDataAddress();
|
|
if (copy != NULL)
|
|
{
|
|
MmFreeContiguousMemory(copy);
|
|
AvSetSavedDataAddress(NULL);
|
|
}
|
|
if (device->m_cRefs == 0) return E_FAIL;
|
|
while (device->m_Miniport.IsFlipPending())
|
|
{
|
|
}
|
|
D3DSurface *surface = &device->m_FrameBufferSurfaces[1];
|
|
D3DFORMAT format = PixelJar::GetFormat(surface);
|
|
DWORD width = PixelJar::GetWidth(surface);
|
|
DWORD height = PixelJar::GetHeight(surface);
|
|
HRESULT result = CreateSurfaceWithContiguousHeader(width, height, format, ©);
|
|
if (FAILED(result)) return result;
|
|
D3DDevice_CopyRects(surface, NULL, 0, copy, NULL);
|
|
KickOffAndWaitForIdle();
|
|
void *registerBase = device->m_Miniport.m_RegisterBase;
|
|
DWORD displayMode = device->m_Miniport.m_DisplayMode;
|
|
DWORD step = 0;
|
|
do
|
|
{
|
|
step = AvSetDisplayMode(registerBase, step, displayMode,
|
|
MapToLinearD3DFORMAT(format), PixelJar::GetPitch(copy), copy->Data);
|
|
} while (step);
|
|
DWORD allocationSize = MmQueryAllocationSize(copy);
|
|
MmPersistContiguousMemory(copy, allocationSize, TRUE);
|
|
AvSetSavedDataAddress(copy);
|
|
return S_OK;
|
|
}
|