mirror of
https://github.com/Cesarus85/ringfall-mjolnir-vr.git
synced 2026-10-26 16:00:35 +01:00
372 lines
9.8 KiB
C++
372 lines
9.8 KiB
C++
/* Resource lifetime logic adapted from RXDK-Libs (2026 Team Resurgent).
|
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
* Target-specific behavior and layouts are checked against January COFF/PDB.
|
|
* See libs/d3d8/PROVENANCE.md. */
|
|
#include "device_layout.h"
|
|
#include "resource_internal.h"
|
|
#include "pixeljar.h"
|
|
#include "kernel_memory.h"
|
|
#include "memory_internal.h"
|
|
#pragma code_seg("D3D")
|
|
namespace D3D
|
|
{
|
|
struct PrivateDataNode
|
|
{
|
|
PrivateDataNode *pNext;
|
|
void *pObject;
|
|
GUID guid;
|
|
DWORD size;
|
|
DWORD flags;
|
|
union
|
|
{
|
|
IUnknown *pUnknown;
|
|
BYTE Data[1];
|
|
};
|
|
};
|
|
typedef char PrivateDataNode_size_check[sizeof(PrivateDataNode) == 36 ? 1 : -1];
|
|
static PrivateDataNode *g_pPrivateData;
|
|
|
|
PrivateDataNode *WINAPI FindPrivateData(
|
|
void *object,
|
|
REFGUID guid)
|
|
{
|
|
PrivateDataNode *node = g_pPrivateData;
|
|
/* BUG (original): the January function never advances this list cursor.
|
|
* A nonmatching nonempty head loops forever (target branches +0x18/+0x28).
|
|
* A corrected implementation would advance node = node->pNext, but that
|
|
* change belongs in a separately labeled nonmatching build. */
|
|
while (node != NULL)
|
|
{
|
|
if (node->pObject == object && node->guid == guid)
|
|
{
|
|
return node;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
void WINAPI CleanPrivateData(
|
|
void *object)
|
|
{
|
|
PrivateDataNode *node = g_pPrivateData;
|
|
PrivateDataNode **previous = &g_pPrivateData;
|
|
while (node != NULL)
|
|
{
|
|
if (node->pObject == object)
|
|
{
|
|
*previous = node->pNext;
|
|
if (node->flags & D3DSPD_IUNKNOWN)
|
|
{
|
|
node->pUnknown->Release();
|
|
}
|
|
LocalFree(node);
|
|
node = *previous;
|
|
}
|
|
else
|
|
{
|
|
previous = &node->pNext;
|
|
node = node->pNext;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
BYTE *WINAPI GetDataFromResource(
|
|
D3DResource *resource)
|
|
{
|
|
return (BYTE *)XMETAL_MapToContiguousAddress(resource->Data);
|
|
}
|
|
void WINAPI DestroyResource(
|
|
D3DResource *resource)
|
|
{
|
|
DWORD type = resource->Common & D3DCOMMON_TYPE_MASK;
|
|
if (type != D3DCOMMON_TYPE_SURFACE || resource->Common & D3DSURFACE_OWNSMEMORY)
|
|
{
|
|
BlockOnResource(resource);
|
|
}
|
|
CleanPrivateData(resource);
|
|
if (type == D3DCOMMON_TYPE_SURFACE)
|
|
{
|
|
if (resource->Common & D3DSURFACE_OWNSMEMORY)
|
|
{
|
|
FreeContiguousMemory(XMETAL_MapToContiguousAddress(resource->Data));
|
|
}
|
|
}
|
|
else if (type == D3DCOMMON_TYPE_PUSHBUFFER)
|
|
{
|
|
if (!(resource->Common & D3DPUSHBUFFER_RUN_USING_CPU_COPY))
|
|
{
|
|
FreeContiguousMemory((void *)resource->Data);
|
|
}
|
|
}
|
|
else if (type != D3DCOMMON_TYPE_INDEXBUFFER && type != D3DCOMMON_TYPE_FIXUP)
|
|
{
|
|
FreeContiguousMemory(XMETAL_MapToContiguousAddress(resource->Data));
|
|
}
|
|
LocalFree(resource);
|
|
return;
|
|
}
|
|
BOOL WINAPI IsResourceSetInDevice(
|
|
D3DResource *resource)
|
|
{
|
|
if (resource->Common & D3DCOMMON_INTREFCOUNT_MASK)
|
|
{
|
|
return TRUE;
|
|
}
|
|
if ((resource->Common & D3DCOMMON_TYPE_MASK) == D3DCOMMON_TYPE_SURFACE)
|
|
{
|
|
D3DBaseTexture *parent = PixelJar::GetParent(resource);
|
|
if (parent && (parent->Common & D3DCOMMON_INTREFCOUNT_MASK))
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
void WINAPI InternalAddRef(
|
|
D3DResource *resource)
|
|
{
|
|
if ((resource->Common & D3DCOMMON_TYPE_MASK) == D3DCOMMON_TYPE_SURFACE)
|
|
{
|
|
if (!(resource->Common & D3DCOMMON_INTREFCOUNT_MASK))
|
|
{
|
|
D3DBaseTexture *parent = PixelJar::GetParent(resource);
|
|
if (parent)
|
|
{
|
|
InternalAddRef(parent);
|
|
}
|
|
}
|
|
}
|
|
resource->Common += 1 << D3DCOMMON_INTREFCOUNT_SHIFT;
|
|
return;
|
|
}
|
|
void WINAPI InternalReleaseSurface(
|
|
D3DResource *resource)
|
|
{
|
|
if ((resource->Common & D3DCOMMON_INTREFCOUNT_MASK) == (1 << D3DCOMMON_INTREFCOUNT_SHIFT))
|
|
{
|
|
D3DBaseTexture *parent = PixelJar::GetParent(resource);
|
|
if (parent)
|
|
{
|
|
InternalRelease(parent);
|
|
}
|
|
if (!(resource->Common & D3DCOMMON_REFCOUNT_MASK))
|
|
{
|
|
DestroyResource(resource);
|
|
return;
|
|
}
|
|
}
|
|
resource->Common -= 1 << D3DCOMMON_INTREFCOUNT_SHIFT;
|
|
return;
|
|
}
|
|
__inline DWORD CDevice::GpuTime(
|
|
void)
|
|
{
|
|
return *m_pGpuTime;
|
|
}
|
|
__inline DWORD CDevice::Age(
|
|
DWORD time)
|
|
{
|
|
return m_CpuTime - time;
|
|
}
|
|
__inline BOOL CDevice::IsTimePending(
|
|
DWORD time)
|
|
{
|
|
return Age(time) < Age(GpuTime());
|
|
}
|
|
}
|
|
using namespace D3D;
|
|
ULONG WINAPI D3DResource_AddRef(
|
|
D3DResource *resource)
|
|
{
|
|
if (!(resource->Common & D3DCOMMON_REFCOUNT_MASK))
|
|
{
|
|
if ((resource->Common & D3DCOMMON_TYPE_MASK) == D3DCOMMON_TYPE_SURFACE)
|
|
{
|
|
D3DBaseTexture *parent = PixelJar::GetParent(resource);
|
|
if (parent)
|
|
{
|
|
parent->AddRef();
|
|
}
|
|
}
|
|
}
|
|
return ++resource->Common & D3DCOMMON_REFCOUNT_MASK;
|
|
}
|
|
ULONG WINAPI D3DResource_Release(
|
|
D3DResource *resource)
|
|
{
|
|
if ((resource->Common & D3DCOMMON_REFCOUNT_MASK) == 1)
|
|
{
|
|
if ((resource->Common & D3DCOMMON_TYPE_MASK) == D3DCOMMON_TYPE_SURFACE)
|
|
{
|
|
D3DBaseTexture *parent = PixelJar::GetParent(resource);
|
|
if (parent)
|
|
{
|
|
parent->Release();
|
|
}
|
|
}
|
|
if (!(resource->Common & D3DCOMMON_INTREFCOUNT_MASK))
|
|
{
|
|
DestroyResource(resource);
|
|
return 0;
|
|
}
|
|
}
|
|
return --resource->Common & D3DCOMMON_REFCOUNT_MASK;
|
|
}
|
|
D3DRESOURCETYPE WINAPI D3DResource_GetType(
|
|
D3DResource *resource)
|
|
{
|
|
DWORD type = resource->Common & D3DCOMMON_TYPE_MASK;
|
|
switch (type)
|
|
{
|
|
case D3DCOMMON_TYPE_VERTEXBUFFER: return D3DRTYPE_VERTEXBUFFER;
|
|
case D3DCOMMON_TYPE_INDEXBUFFER: return D3DRTYPE_INDEXBUFFER;
|
|
case D3DCOMMON_TYPE_PUSHBUFFER: return D3DRTYPE_PUSHBUFFER;
|
|
case D3DCOMMON_TYPE_FIXUP: return D3DRTYPE_FIXUP;
|
|
case D3DCOMMON_TYPE_PALETTE: return D3DRTYPE_PALETTE;
|
|
case D3DCOMMON_TYPE_TEXTURE:
|
|
{
|
|
DWORD format = ((D3DBaseTexture *)resource)->Format;
|
|
if (format & D3DFORMAT_CUBEMAP) return D3DRTYPE_CUBETEXTURE;
|
|
else if ((format & D3DFORMAT_DIMENSION_MASK) > (2 << D3DFORMAT_DIMENSION_SHIFT)) return D3DRTYPE_VOLUMETEXTURE;
|
|
else return D3DRTYPE_TEXTURE;
|
|
}
|
|
case D3DCOMMON_TYPE_SURFACE:
|
|
{
|
|
DWORD format = ((D3DPixelContainer *)resource)->Format;
|
|
if ((format & D3DFORMAT_DIMENSION_MASK) > (2 << D3DFORMAT_DIMENSION_SHIFT)) return D3DRTYPE_VOLUME;
|
|
else return D3DRTYPE_SURFACE;
|
|
}
|
|
default: return (D3DRESOURCETYPE)0;
|
|
}
|
|
}
|
|
BOOL WINAPI D3DResource_IsBusy(
|
|
D3DResource *resource)
|
|
{
|
|
CDevice *device = g_pDevice;
|
|
D3DResource *parent = PixelJar::GetParent(resource);
|
|
if (parent)
|
|
{
|
|
if (IsResourceSetInDevice(resource)) return TRUE;
|
|
resource = parent;
|
|
}
|
|
if (IsResourceSetInDevice(resource)) return TRUE;
|
|
BOOL result = resource->Lock != 0 && device->IsTimePending(resource->Lock);
|
|
if (!result) resource->Lock = 0;
|
|
return result;
|
|
}
|
|
void WINAPI D3DResource_GetDevice(
|
|
D3DResource *resource,
|
|
D3DDevice **device)
|
|
{
|
|
*device = g_pDevice;
|
|
g_pDevice->AddRef();
|
|
return;
|
|
}
|
|
void WINAPI D3DResource_Register(
|
|
D3DResource *resource,
|
|
void *base)
|
|
{
|
|
DWORD type = resource->Common & D3DCOMMON_TYPE_MASK;
|
|
void *memory = (BYTE *)base + resource->Data;
|
|
if (type == D3DCOMMON_TYPE_PUSHBUFFER)
|
|
{
|
|
resource->Data = (DWORD)memory;
|
|
}
|
|
else
|
|
{
|
|
resource->Data = XMETAL_MapToPhysicalOffset(memory);
|
|
}
|
|
return;
|
|
}
|
|
void WINAPI D3DResource_BlockUntilNotBusy(
|
|
D3DResource *resource)
|
|
{
|
|
BlockOnResource(resource);
|
|
return;
|
|
}
|
|
HRESULT WINAPI D3DResource_SetPrivateData(
|
|
D3DResource *resource,
|
|
REFGUID guid,
|
|
const void *data,
|
|
DWORD size,
|
|
DWORD flags)
|
|
{
|
|
PrivateDataNode *node = FindPrivateData(resource, guid);
|
|
if (node) D3DResource_FreePrivateData(resource, guid);
|
|
node = (PrivateDataNode *)LocalAlloc(LMEM_ZEROINIT, sizeof(PrivateDataNode) + size);
|
|
if (!node) return E_OUTOFMEMORY;
|
|
node->size = size;
|
|
node->guid = guid;
|
|
node->flags = flags;
|
|
node->pObject = resource;
|
|
if (flags & D3DSPD_IUNKNOWN)
|
|
{
|
|
node->pUnknown = (IUnknown *)data;
|
|
node->pUnknown->AddRef();
|
|
}
|
|
else
|
|
{
|
|
memcpy((BYTE *)node + offsetof(PrivateDataNode, Data), data, size);
|
|
}
|
|
node->pNext = g_pPrivateData;
|
|
g_pPrivateData = node;
|
|
return D3D_OK;
|
|
}
|
|
HRESULT WINAPI D3DResource_GetPrivateData(
|
|
D3DResource *resource,
|
|
REFGUID guid,
|
|
void *data,
|
|
DWORD *size)
|
|
{
|
|
PrivateDataNode *node = FindPrivateData(resource, guid);
|
|
if (!node) return D3DERR_NOTFOUND;
|
|
if (!data)
|
|
{
|
|
*size = node->size;
|
|
return D3D_OK;
|
|
}
|
|
if (*size < node->size)
|
|
{
|
|
*size = node->size;
|
|
return D3DERR_MOREDATA;
|
|
}
|
|
*size = node->size;
|
|
if (node->flags & D3DSPD_IUNKNOWN)
|
|
{
|
|
*(IUnknown **)data = node->pUnknown;
|
|
node->pUnknown->AddRef();
|
|
return D3D_OK;
|
|
}
|
|
memcpy(data, (BYTE *)node + offsetof(PrivateDataNode, Data), node->size);
|
|
return D3D_OK;
|
|
}
|
|
void WINAPI D3DResource_FreePrivateData(
|
|
D3DResource *resource,
|
|
REFGUID guid)
|
|
{
|
|
PrivateDataNode *node = g_pPrivateData;
|
|
PrivateDataNode **previous = &g_pPrivateData;
|
|
while (node)
|
|
{
|
|
if (node->pObject == resource && node->guid == guid)
|
|
{
|
|
*previous = node->pNext;
|
|
if (node->flags & D3DSPD_IUNKNOWN) node->pUnknown->Release();
|
|
LocalFree(node);
|
|
return;
|
|
}
|
|
previous = &node->pNext;
|
|
node = node->pNext;
|
|
}
|
|
return;
|
|
}
|
|
|
|
namespace D3D
|
|
{
|
|
/* Original externally linked video-address conversion, not an emission shim. */
|
|
void *WINAPI GetVideoAddress(
|
|
DWORD address)
|
|
{
|
|
return XMETAL_MapToVideoAddress(address);
|
|
}
|
|
}
|