Files
Cesarus85--mjolnir-vr/libs/d3d8/resource.cpp
T

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);
}
}