/* Device initialization adapted from RXDK-Libs, 2026 Team Resurgent. * SPDX-License-Identifier: GPL-3.0-or-later * The original January code/PDB determines context handles, layouts and order. */ #include "dxgcreate_internal.h" #include "push_internal.h" #include "lazy_internal.h" #include "math_internal.h" #include "resource_internal.h" #include "kernel_memory.h" #include "display_internal.h" #include "pusher_state.h" #include "miniport_constants.h" #include "vshader_internal.h" #include "surface_internal.h" #include "pixeljar.h" #include "memory_internal.h" #pragma code_seg("D3D") namespace D3D { #include "initial_states.inc" DWORD CDevice::m_PushBufferSize; DWORD CDevice::m_PushSegmentSize; void WINAPI InitializeKelvin( void) { CDevice *device = g_pDevice; DWORD *push = device->StartPush(); PushCount(push, 0x180, 3); push[1] = NV_DD_DMA_PUSHER_SYNC_NOTIFIER_CONTEXT_DMA_TO_MEMORY; push[2] = NV_DD_DMA_CONTEXT_DMA_IN_VIDEO_MEMORY; push[3] = NV_DD_DMA_CONTEXT_DMA_IN_VIDEO_MEMORY; PushCount(push + 4, 0x190, 6); push[5] = NV_DD_DMA_CONTEXT_DMA_TO_VIDEO_MEMORY; push[6] = D3D_COLOR_CONTEXT_DMA_IN_VIDEO_MEMORY; push[7] = D3D_ZETA_CONTEXT_DMA_IN_VIDEO_MEMORY; push[8] = NV_DD_DMA_CONTEXT_DMA_IN_VIDEO_MEMORY; push[9] = NV_DD_DMA_CONTEXT_DMA_IN_VIDEO_MEMORY; push[10] = D3D_SEMAPHORE_CONTEXT_DMA_IN_MEMORY; PushCount(push + 11, 0x1a8, 1); push[12] = D3D_CONTEXT_IN_CACHED_MEMORY; Push1(push + 13, 0x1d6c, 0); device->EndPush(push + 15); push = device->StartPush(); Push1(push, 0x9fc, 1); PushCount(push + 2, 0xa50, 4); push[3] = NV_FLOAT_ZERO; push[4] = NV_FLOAT_ZERO; push[5] = NV_FLOAT_ZERO; push[6] = NV_FLOAT_ONE; Push1(push + 7, 0x16bc, TRUE); Push1(push + 9, 0x1e78, 0x210000); Push1(push + 11, 0x1d80, TRUE); Push1(push + 13, 0x1e68, NV_FLOAT_POSITIVE_INFINITY); Push1(push + 15, 0x1d78, TRUE); device->EndPush(push + 17); device->SetShaderConstantMode(D3DSCM_96CONSTANTS); return; } void WINAPI InitializeHardware( void) { CDevice *device = g_pDevice; DWORD *push = device->StartPush(); Push1(push, 0x4000, D3D_MEMORY_TO_MEMORY_COPY); Push1(push + 2, 0x6000, D3D_RECTANGLE_COPY); Push1(push + 4, 0x8000, D3D_RECTANGLE_COPY_SURFACES); Push1(push + 6, 0x0000, D3D_KELVIN_PRIMITIVE); push += 8; Push1(push, 0x4180, D3D_MEMCOPY_NOTIFIER_CONTEXT_DMA_TO_MEMORY); Push1(push + 2, 0x619c, D3D_RECTANGLE_COPY_SURFACES); Push1(push + 4, 0x62fc, 3); /* SRCCOPY operation. */ Push2(push + 6, 0x8184, NV_DD_DMA_CONTEXT_DMA_IN_VIDEO_MEMORY, D3D_COPY_CONTEXT_DMA_IN_VIDEO_MEMORY); device->EndPush(push + 9); InitializeKelvin(); return; } void WINAPI InitializeD3dState( void) { CDevice *device = g_pDevice; DWORD i; for (i = 0; i < D3DTS_MAX; i++) device->SetTransform((D3DTRANSFORMSTATETYPE)i, &g_IdentityMatrix); for (i = D3DRS_PS_MAX; i < D3DRS_MAX; i++) { if (i != D3DRS_MULTISAMPLETYPE) device->SetRenderStateNotInline((D3DRENDERSTATETYPE)i, g_InitialRenderStates[i - D3DRS_PS_MAX]); } device->SetRenderStateNotInline(D3DRS_ZENABLE, device->m_pAutoDepthBuffer != NULL); for (DWORD stage = 0; stage < D3DTSS_MAXSTAGES; stage++) { for (i = 0; i < D3DTSS_MAX; i++) device->SetTextureStageStateNotInline(stage, (D3DTEXTURESTAGESTATETYPE)i, g_InitialTextureStates[i]); device->SetTextureStageStateNotInline(stage, D3DTSS_TEXCOORDINDEX, stage); } device->SetTextureStageStateNotInline(0, D3DTSS_COLOROP, D3DTOP_MODULATE); device->SetTextureStageStateNotInline(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); return; } void CDevice::FreeFrameBuffers( void) { if (AvGetSavedDataAddress() == NULL) AvSendTVEncoderOption(m_Miniport.m_RegisterBase, AV_OPTION_BLANK_SCREEN, TRUE, NULL); if (m_pRenderTarget != NULL) { RecordSurfaceWritePush(m_pRenderTarget); InternalReleaseSurface(m_pRenderTarget); m_pRenderTarget = NULL; } if (m_pZBuffer != NULL) { RecordSurfaceWritePush(m_pZBuffer); InternalReleaseSurface(m_pZBuffer); m_pZBuffer = NULL; } if (m_pAutoDepthBuffer != NULL) { SetTile(1, NULL); FreeContiguousMemory(m_pAutoDepthBuffer); m_pAutoDepthBuffer = NULL; ZeroMemory(&m_AutoDepthSurface, sizeof(m_AutoDepthSurface)); } if (m_pFrameBufferBase != NULL) { SetTile(0, NULL); FreeContiguousMemory(m_pFrameBufferBase); m_pFrameBufferBase = NULL; ZeroMemory(m_FrameBufferSurfaces, sizeof(m_FrameBufferSurfaces)); } if (m_pAntiAliasBufferBase != NULL) { FreeContiguousMemory(m_pAntiAliasBufferBase); m_pAntiAliasBufferBase = NULL; } return; } HRESULT WINAPI PresentationParametersParameterCheck( D3DPRESENT_PARAMETERS *parameters) { DWORD sampleType = parameters->MultiSampleType; if (sampleType != D3DMULTISAMPLE_NONE && sampleType != 0) { if ((sampleType & 0x000f0000UL) > D3DMULTISAMPLE_PREFILTER_FORMAT_A8R8G8B8) return D3DERR_INVALIDCALL; if (((sampleType >> 4) & 15) < 1 || (sampleType & 15) < 1 || ((sampleType >> 4) & 15) > 3 || (sampleType & 15) > 3) return D3DERR_INVALIDCALL; } DWORD interval = parameters->FullScreen_PresentationInterval; if (interval > D3DPRESENT_INTERVAL_TWO && interval != D3DPRESENT_INTERVAL_IMMEDIATE) return D3DERR_INVALIDCALL; D3DSWAPEFFECT effect = parameters->SwapEffect; if (effect != D3DSWAPEFFECT_DISCARD && effect != D3DSWAPEFFECT_FLIP && effect != 0) return D3DERR_INVALIDCALL; if (parameters->BackBufferCount > 2) return D3DERR_INVALIDCALL; return S_OK; } /* The January owner frees the push allocation directly. It does not use the * later SDK's UninitializePushBuffer path. Completion requires GPU progress. */ void CDevice::UnInit( void) { DWORD i; if (m_Pusher.m_pPut != NULL) { KickOffAndWaitForIdle(); *m_Pusher.m_pPut = ((DWORD)m_pPushBase & 0x0fffffffUL) + 1; m_Pusher.m_pPut = m_pPushBase; KickOff(); while (((DWORD)HwGet() & 0x0fffffffUL) != ((DWORD)m_pPushBase & 0x0fffffffUL)) { BusyLoop(); } } while (m_Miniport.IsFlipPending()) { } FreeFrameBuffers(); if (m_pIndexBuffer != NULL) InternalRelease(m_pIndexBuffer); for (i = 0; i < D3DTSS_MAXSTAGES; i++) { if (m_Textures[i] != NULL) InternalRelease(m_Textures[i]); if (m_Palettes[i] != NULL) InternalRelease(m_Palettes[i]); } for (i = 0; i < 16; i++) { if (g_Stream[i].pVertexBuffer != NULL) InternalRelease(g_Stream[i].pVertexBuffer); } for (i = 0; i < 16; i++) { if (m_ReportAllocations[i] != NULL) MmFreeContiguousMemory(m_ReportAllocations[i]); } if (m_pCachedContiguousMemoryBase != NULL) MmFreeContiguousMemory(m_pCachedContiguousMemoryBase); if (m_pPushBase != NULL) MmFreeContiguousMemory(m_pPushBase); if (m_pLights != NULL) LocalFree(m_pLights); if (m_Miniport.m_RegisterBase != NULL) { m_Miniport.DisableInterrupts(); m_Miniport.ShutdownEngines(); } ZeroMemory(g_Stream, sizeof(g_Stream)); return; } /* January stores surface headers inside CDevice and allocates the pixel planes * separately. Creation/Reset own cleanup of any partial allocations on failure. * Width/height/counts and multisample encodings must be valid checked API values. */ HRESULT CDevice::InitializeFrameBuffers( D3DPRESENT_PARAMETERS *parameters) { DWORD format; DWORD size; D3DTILE tile; DWORD i; DWORD backBufferCount = max(1, parameters->BackBufferCount); D3DFORMAT postfilterFormat = MapToLinearD3DFORMAT(parameters->BackBufferFormat); D3DFORMAT autoDepthStencilFormat = MapToLinearD3DFORMAT(parameters->AutoDepthStencilFormat); DWORD backBufferWidth = parameters->BackBufferWidth; DWORD backBufferHeight = parameters->BackBufferHeight; m_PresentationInterval = parameters->FullScreen_PresentationInterval; m_DisplayWidth = backBufferWidth; m_DisplayHeight = backBufferHeight; DWORD frameCount = backBufferCount + 1; m_FrameBufferCount = frameCount; /* Preserve January's low-word render-state storage. Its later prefilter * selector consequently has only the retained state bits available. */ D3D__RenderState[D3DRS_MULTISAMPLETYPE] = parameters->MultiSampleType & 0xffff; BOOL doAntiAlias = D3D__RenderState[D3DRS_MULTISAMPLETYPE] & 0x3000; if (!doAntiAlias) D3D__RenderState[D3DRS_MULTISAMPLETYPE] = D3DMULTISAMPLE_NONE; D3DFORMAT prefilterFormat = postfilterFormat; switch (D3D__RenderState[D3DRS_MULTISAMPLETYPE] & 0xf0000) { case D3DMULTISAMPLE_PREFILTER_FORMAT_X1R5G5B5: prefilterFormat = D3DFMT_LIN_X1R5G5B5; break; case D3DMULTISAMPLE_PREFILTER_FORMAT_R5G6B5: prefilterFormat = D3DFMT_LIN_R5G6B5; break; case D3DMULTISAMPLE_PREFILTER_FORMAT_X8R8G8B8: prefilterFormat = D3DFMT_LIN_X8R8G8B8; break; case D3DMULTISAMPLE_PREFILTER_FORMAT_A8R8G8B8: prefilterFormat = D3DFMT_LIN_A8R8G8B8; break; } DWORD width = backBufferWidth * ((D3D__RenderState[D3DRS_MULTISAMPLETYPE] >> 4) & 15); DWORD height = backBufferHeight * (D3D__RenderState[D3DRS_MULTISAMPLETYPE] & 15); DWORD frameSize = PixelJar::EncodeFormat(width, height, 1, 1, prefilterFormat, CalcTilePitch(width, prefilterFormat), true, false, false, &format, &size); frameCount = doAntiAlias ? 1 : frameCount; DWORD allocationSize = (frameCount * frameSize + D3DTILE_ALIGNMENT - 1) & ~(D3DTILE_ALIGNMENT - 1); BYTE *memory = (BYTE *)D3D::AllocateContiguousMemory(allocationSize, D3DTILE_ALIGNMENT); if (memory == NULL) return E_OUTOFMEMORY; m_pFrameBufferBase = memory; for (i = 0; i < frameCount; i++) { InitializeSurface(&m_FrameBufferSurfaces[i], format, size, memory); memory += frameSize; } /* Original 1920-wide display path leaves these allocations untiled. */ if (width != 1920) { /* Ignored depth fields are initialized as well: do not copy * indeterminate members through the SetTile value assignment. */ tile.ZOffset = 0; tile.ZStartTag = 0; tile.Flags = 0; tile.pMemory = m_pFrameBufferBase; tile.Size = allocationSize; tile.Pitch = PixelJar::GetPitch(&m_FrameBufferSurfaces[0]); SetTile(0, &tile); } if (parameters->EnableAutoDepthStencil) { frameSize = PixelJar::EncodeFormat(width, height, 1, 1, autoDepthStencilFormat, CalcTilePitch(width, autoDepthStencilFormat), true, false, false, &format, &size); allocationSize = (frameSize + D3DTILE_ALIGNMENT - 1) & ~(D3DTILE_ALIGNMENT - 1); memory = (BYTE *)D3D::AllocateContiguousMemory(allocationSize, D3DTILE_ALIGNMENT); if (memory == NULL) return E_OUTOFMEMORY; m_pAutoDepthBuffer = memory; InitializeSurface(&m_AutoDepthSurface, format, size, memory); if (width != 1920) { tile.Flags = D3DTILE_FLAGS_ZBUFFER | D3DTILE_FLAGS_ZCOMPRESS; tile.pMemory = memory; tile.Size = allocationSize; tile.Pitch = PixelJar::GetPitch(&m_AutoDepthSurface); tile.ZOffset = 0; tile.ZStartTag = 0; if (BitsPerPixelOfD3DFORMAT(autoDepthStencilFormat) == 32) tile.Flags |= D3DTILE_FLAGS_Z32BITS; SetTile(1, &tile); } } if (doAntiAlias) { frameSize = PixelJar::EncodeFormat(backBufferWidth, backBufferHeight, 1, 1, postfilterFormat, 0, true, false, false, &format, &size); memory = (BYTE *)D3D::AllocateContiguousMemory(backBufferCount * frameSize, D3DTILE_ALIGNMENT); if (memory == NULL) return E_OUTOFMEMORY; m_pAntiAliasBufferBase = memory; for (i = 1; i <= backBufferCount; i++) { InitializeSurface(&m_FrameBufferSurfaces[i], format, size, memory); memory += frameSize; } } DWORD *push = StartPush(); DWORD flipLimit = doAntiAlias ? 2 : m_FrameBufferCount; PushCount(push, 0x120, 3); push[1] = 0; push[2] = 1; push[3] = flipLimit; EndPush(push + 4); return S_OK; } }