Merge branch 'gl-texture-management' into 'next'

Manage uploaded OpenGL textures with an internal list

Closes #411

See merge request STJr/SRB2!1391
This commit is contained in:
SteelT 2021-02-07 13:37:33 -05:00
commit 6089550972
11 changed files with 106 additions and 88 deletions

View File

@ -2546,28 +2546,28 @@ static void F_UnloadAlacroixGraphics(SINT8 oldttscale)
oldttscale--; // zero-based index oldttscale--; // zero-based index
for (i = 0; i < TTMAX_ALACROIX; i++) for (i = 0; i < TTMAX_ALACROIX; i++)
{ {
if(ttembl[oldttscale][i]) { Z_Free(ttembl[oldttscale][i]); ttembl[oldttscale][i] = 0; } if(ttembl[oldttscale][i]) { Patch_Free(ttembl[oldttscale][i]); ttembl[oldttscale][i] = 0; }
if(ttribb[oldttscale][i]) { Z_Free(ttribb[oldttscale][i]); ttribb[oldttscale][i] = 0; } if(ttribb[oldttscale][i]) { Patch_Free(ttribb[oldttscale][i]); ttribb[oldttscale][i] = 0; }
if(ttsont[oldttscale][i]) { Z_Free(ttsont[oldttscale][i]); ttsont[oldttscale][i] = 0; } if(ttsont[oldttscale][i]) { Patch_Free(ttsont[oldttscale][i]); ttsont[oldttscale][i] = 0; }
if(ttrobo[oldttscale][i]) { Z_Free(ttrobo[oldttscale][i]); ttrobo[oldttscale][i] = 0; } if(ttrobo[oldttscale][i]) { Patch_Free(ttrobo[oldttscale][i]); ttrobo[oldttscale][i] = 0; }
if(tttwot[oldttscale][i]) { Z_Free(tttwot[oldttscale][i]); tttwot[oldttscale][i] = 0; } if(tttwot[oldttscale][i]) { Patch_Free(tttwot[oldttscale][i]); tttwot[oldttscale][i] = 0; }
if(ttrbtx[oldttscale][i]) { Z_Free(ttrbtx[oldttscale][i]); ttrbtx[oldttscale][i] = 0; } if(ttrbtx[oldttscale][i]) { Patch_Free(ttrbtx[oldttscale][i]); ttrbtx[oldttscale][i] = 0; }
if(ttsoib[oldttscale][i]) { Z_Free(ttsoib[oldttscale][i]); ttsoib[oldttscale][i] = 0; } if(ttsoib[oldttscale][i]) { Patch_Free(ttsoib[oldttscale][i]); ttsoib[oldttscale][i] = 0; }
if(ttsoif[oldttscale][i]) { Z_Free(ttsoif[oldttscale][i]); ttsoif[oldttscale][i] = 0; } if(ttsoif[oldttscale][i]) { Patch_Free(ttsoif[oldttscale][i]); ttsoif[oldttscale][i] = 0; }
if(ttsoba[oldttscale][i]) { Z_Free(ttsoba[oldttscale][i]); ttsoba[oldttscale][i] = 0; } if(ttsoba[oldttscale][i]) { Patch_Free(ttsoba[oldttscale][i]); ttsoba[oldttscale][i] = 0; }
if(ttsobk[oldttscale][i]) { Z_Free(ttsobk[oldttscale][i]); ttsobk[oldttscale][i] = 0; } if(ttsobk[oldttscale][i]) { Patch_Free(ttsobk[oldttscale][i]); ttsobk[oldttscale][i] = 0; }
if(ttsodh[oldttscale][i]) { Z_Free(ttsodh[oldttscale][i]); ttsodh[oldttscale][i] = 0; } if(ttsodh[oldttscale][i]) { Patch_Free(ttsodh[oldttscale][i]); ttsodh[oldttscale][i] = 0; }
if(tttaib[oldttscale][i]) { Z_Free(tttaib[oldttscale][i]); tttaib[oldttscale][i] = 0; } if(tttaib[oldttscale][i]) { Patch_Free(tttaib[oldttscale][i]); tttaib[oldttscale][i] = 0; }
if(tttaif[oldttscale][i]) { Z_Free(tttaif[oldttscale][i]); tttaif[oldttscale][i] = 0; } if(tttaif[oldttscale][i]) { Patch_Free(tttaif[oldttscale][i]); tttaif[oldttscale][i] = 0; }
if(tttaba[oldttscale][i]) { Z_Free(tttaba[oldttscale][i]); tttaba[oldttscale][i] = 0; } if(tttaba[oldttscale][i]) { Patch_Free(tttaba[oldttscale][i]); tttaba[oldttscale][i] = 0; }
if(tttabk[oldttscale][i]) { Z_Free(tttabk[oldttscale][i]); tttabk[oldttscale][i] = 0; } if(tttabk[oldttscale][i]) { Patch_Free(tttabk[oldttscale][i]); tttabk[oldttscale][i] = 0; }
if(tttabt[oldttscale][i]) { Z_Free(tttabt[oldttscale][i]); tttabt[oldttscale][i] = 0; } if(tttabt[oldttscale][i]) { Patch_Free(tttabt[oldttscale][i]); tttabt[oldttscale][i] = 0; }
if(tttaft[oldttscale][i]) { Z_Free(tttaft[oldttscale][i]); tttaft[oldttscale][i] = 0; } if(tttaft[oldttscale][i]) { Patch_Free(tttaft[oldttscale][i]); tttaft[oldttscale][i] = 0; }
if(ttknib[oldttscale][i]) { Z_Free(ttknib[oldttscale][i]); ttknib[oldttscale][i] = 0; } if(ttknib[oldttscale][i]) { Patch_Free(ttknib[oldttscale][i]); ttknib[oldttscale][i] = 0; }
if(ttknif[oldttscale][i]) { Z_Free(ttknif[oldttscale][i]); ttknif[oldttscale][i] = 0; } if(ttknif[oldttscale][i]) { Patch_Free(ttknif[oldttscale][i]); ttknif[oldttscale][i] = 0; }
if(ttknba[oldttscale][i]) { Z_Free(ttknba[oldttscale][i]); ttknba[oldttscale][i] = 0; } if(ttknba[oldttscale][i]) { Patch_Free(ttknba[oldttscale][i]); ttknba[oldttscale][i] = 0; }
if(ttknbk[oldttscale][i]) { Z_Free(ttknbk[oldttscale][i]); ttknbk[oldttscale][i] = 0; } if(ttknbk[oldttscale][i]) { Patch_Free(ttknbk[oldttscale][i]); ttknbk[oldttscale][i] = 0; }
if(ttkndh[oldttscale][i]) { Z_Free(ttkndh[oldttscale][i]); ttkndh[oldttscale][i] = 0; } if(ttkndh[oldttscale][i]) { Patch_Free(ttkndh[oldttscale][i]); ttkndh[oldttscale][i] = 0; }
} }
ttloaded[oldttscale] = false; ttloaded[oldttscale] = false;
} }

View File

@ -1091,7 +1091,6 @@ void HWR_UnlockCachedPatch(GLPatch_t *gpatch)
return; return;
Z_ChangeTag(gpatch->mipmap->data, PU_HWRCACHE_UNLOCKED); Z_ChangeTag(gpatch->mipmap->data, PU_HWRCACHE_UNLOCKED);
Z_ChangeTag(gpatch, PU_HWRPATCHINFO_UNLOCKED);
} }
static const INT32 picmode2GR[] = static const INT32 picmode2GR[] =

View File

@ -48,44 +48,43 @@ struct GLColormap_s
typedef struct GLColormap_s GLColormap_t; typedef struct GLColormap_s GLColormap_t;
// data holds the address of the graphics data cached in heap memory // Texture information (misleadingly named "mipmap" all over the code.)
// NULL if the texture is not in Doom heap cache. // The *data pointer holds the address of the graphics data cached in heap memory.
// NULL if the texture is not in SRB2's heap cache.
struct GLMipmap_s struct GLMipmap_s
{ {
// for TexDownloadMipMap // for UpdateTexture
GLTextureFormat_t format; GLTextureFormat_t format;
void *data; void *data;
UINT32 flags; UINT32 flags;
UINT16 height; UINT16 height;
UINT16 width; UINT16 width;
UINT32 downloaded; // The GPU has this texture. UINT32 downloaded; // The GPU has this texture.
struct GLMipmap_s *nextcolormap; struct GLMipmap_s *nextcolormap;
struct GLColormap_s *colormap; struct GLColormap_s *colormap;
struct GLMipmap_s *nextmipmap; // Linked list of all textures
}; };
typedef struct GLMipmap_s GLMipmap_t; typedef struct GLMipmap_s GLMipmap_t;
// //
// Doom texture info, as cached for hardware rendering // Level textures, as cached for hardware rendering.
// //
struct GLMapTexture_s struct GLMapTexture_s
{ {
GLMipmap_t mipmap; GLMipmap_t mipmap;
float scaleX; //used for scaling textures on walls float scaleX; // Used for scaling textures on walls
float scaleY; float scaleY;
}; };
typedef struct GLMapTexture_s GLMapTexture_t; typedef struct GLMapTexture_s GLMapTexture_t;
// a cached patch as converted to hardware format // Patch information for the hardware renderer.
struct GLPatch_s struct GLPatch_s
{ {
float max_s,max_t; GLMipmap_t *mipmap; // Texture data. Allocated whenever the patch is.
GLMipmap_t *mipmap; float max_s, max_t;
}; };
typedef struct GLPatch_s GLPatch_t; typedef struct GLPatch_s GLPatch_t;

View File

@ -255,7 +255,16 @@ enum ETextureFlags
TF_TRANSPARENT = 0x00000040, // texture with some alpha == 0 TF_TRANSPARENT = 0x00000040, // texture with some alpha == 0
}; };
typedef struct GLMipmap_s FTextureInfo; struct FTextureInfo
{
UINT32 width, height;
UINT32 downloaded;
UINT32 format;
struct GLMipmap_s *texture;
struct FTextureInfo *prev, *next;
};
typedef struct FTextureInfo FTextureInfo;
// jimita 14032019 // jimita 14032019
struct FLightInfo struct FLightInfo

View File

@ -40,13 +40,12 @@ EXPORT void HWRAPI(DrawIndexedTriangles) (FSurfaceInfo *pSurf, FOutVector *pOutV
EXPORT void HWRAPI(RenderSkyDome) (gl_sky_t *sky); EXPORT void HWRAPI(RenderSkyDome) (gl_sky_t *sky);
EXPORT void HWRAPI(SetBlend) (FBITFIELD PolyFlags); EXPORT void HWRAPI(SetBlend) (FBITFIELD PolyFlags);
EXPORT void HWRAPI(ClearBuffer) (FBOOLEAN ColorMask, FBOOLEAN DepthMask, FRGBAFloat *ClearColor); EXPORT void HWRAPI(ClearBuffer) (FBOOLEAN ColorMask, FBOOLEAN DepthMask, FRGBAFloat *ClearColor);
EXPORT void HWRAPI(SetTexture) (FTextureInfo *TexInfo); EXPORT void HWRAPI(SetTexture) (GLMipmap_t *TexInfo);
EXPORT void HWRAPI(UpdateTexture) (FTextureInfo *TexInfo); EXPORT void HWRAPI(UpdateTexture) (GLMipmap_t *TexInfo);
EXPORT void HWRAPI(DeleteTexture) (FTextureInfo *TexInfo); EXPORT void HWRAPI(DeleteTexture) (GLMipmap_t *TexInfo);
EXPORT void HWRAPI(ReadRect) (INT32 x, INT32 y, INT32 width, INT32 height, INT32 dst_stride, UINT16 *dst_data); EXPORT void HWRAPI(ReadRect) (INT32 x, INT32 y, INT32 width, INT32 height, INT32 dst_stride, UINT16 *dst_data);
EXPORT void HWRAPI(GClipRect) (INT32 minx, INT32 miny, INT32 maxx, INT32 maxy, float nearclip); EXPORT void HWRAPI(GClipRect) (INT32 minx, INT32 miny, INT32 maxx, INT32 maxy, float nearclip);
EXPORT void HWRAPI(ClearMipMapCache) (void); EXPORT void HWRAPI(ClearMipMapCache) (void);
EXPORT void HWRAPI(ClearCacheList) (void);
//Hurdler: added for backward compatibility //Hurdler: added for backward compatibility
EXPORT void HWRAPI(SetSpecialState) (hwdspecialstate_t IdState, INT32 Value); EXPORT void HWRAPI(SetSpecialState) (hwdspecialstate_t IdState, INT32 Value);
@ -101,7 +100,6 @@ struct hwdriver_s
ReadRect pfnReadRect; ReadRect pfnReadRect;
GClipRect pfnGClipRect; GClipRect pfnGClipRect;
ClearMipMapCache pfnClearMipMapCache; ClearMipMapCache pfnClearMipMapCache;
ClearCacheList pfnClearCacheList;
SetSpecialState pfnSetSpecialState;//Hurdler: added for backward compatibility SetSpecialState pfnSetSpecialState;//Hurdler: added for backward compatibility
DrawModel pfnDrawModel; DrawModel pfnDrawModel;
CreateModelVBOs pfnCreateModelVBOs; CreateModelVBOs pfnCreateModelVBOs;

View File

@ -58,8 +58,9 @@ static GLuint tex_downloaded = 0;
static GLfloat fov = 90.0f; static GLfloat fov = 90.0f;
static FBITFIELD CurrentPolyFlags; static FBITFIELD CurrentPolyFlags;
static FTextureInfo *gl_cachetail = NULL; // Linked list of all textures.
static FTextureInfo *gl_cachehead = NULL; static FTextureInfo *TexCacheTail = NULL;
static FTextureInfo *TexCacheHead = NULL;
RGBA_t myPaletteData[256]; RGBA_t myPaletteData[256];
GLint screen_width = 0; // used by Draw2DLine() GLint screen_width = 0; // used by Draw2DLine()
@ -1287,10 +1288,30 @@ void SetStates(void)
// -----------------+ // -----------------+
// DeleteTexture : Deletes a texture from the GPU and frees its data // DeleteTexture : Deletes a texture from the GPU and frees its data
// -----------------+ // -----------------+
EXPORT void HWRAPI(DeleteTexture) (FTextureInfo *pTexInfo) EXPORT void HWRAPI(DeleteTexture) (GLMipmap_t *pTexInfo)
{ {
if (pTexInfo->downloaded) FTextureInfo *head = TexCacheHead;
if (!pTexInfo)
return;
else if (pTexInfo->downloaded)
pglDeleteTextures(1, (GLuint *)&pTexInfo->downloaded); pglDeleteTextures(1, (GLuint *)&pTexInfo->downloaded);
while (head)
{
if (head->downloaded == pTexInfo->downloaded)
{
if (head->next)
head->next->prev = head->prev;
if (head->prev)
head->prev->next = head->next;
free(head);
break;
}
head = head->next;
}
pTexInfo->downloaded = 0; pTexInfo->downloaded = 0;
} }
@ -1303,26 +1324,29 @@ void Flush(void)
{ {
//GL_DBG_Printf ("HWR_Flush()\n"); //GL_DBG_Printf ("HWR_Flush()\n");
while (gl_cachehead) while (TexCacheHead)
{ {
DeleteTexture(gl_cachehead); FTextureInfo *pTexInfo = TexCacheHead;
gl_cachehead = gl_cachehead->nextmipmap; GLMipmap_t *texture = pTexInfo->texture;
if (pTexInfo->downloaded)
{
pglDeleteTextures(1, (GLuint *)&pTexInfo->downloaded);
pTexInfo->downloaded = 0;
}
if (texture)
texture->downloaded = 0;
TexCacheHead = pTexInfo->next;
free(pTexInfo);
} }
ClearCacheList(); //Hurdler: well, gl_cachehead is already NULL TexCacheTail = TexCacheHead = NULL; //Hurdler: well, TexCacheHead is already NULL
tex_downloaded = 0; tex_downloaded = 0;
} }
// -----------------+
// ClearCacheList : Clears the texture cache tail and head
// -----------------+
EXPORT void HWRAPI(ClearCacheList) (void)
{
gl_cachetail = gl_cachehead = NULL;
}
// -----------------+ // -----------------+
// isExtAvailable : Look if an OpenGL extension is available // isExtAvailable : Look if an OpenGL extension is available
// Returns : true if extension available // Returns : true if extension available
@ -1718,7 +1742,7 @@ EXPORT void HWRAPI(SetBlend) (FBITFIELD PolyFlags)
// -----------------+ // -----------------+
// UpdateTexture : Updates the texture data. // UpdateTexture : Updates the texture data.
// -----------------+ // -----------------+
EXPORT void HWRAPI(UpdateTexture) (FTextureInfo *pTexInfo) EXPORT void HWRAPI(UpdateTexture) (GLMipmap_t *pTexInfo)
{ {
// Download a mipmap // Download a mipmap
boolean updatemipmap = true; boolean updatemipmap = true;
@ -1920,7 +1944,7 @@ EXPORT void HWRAPI(UpdateTexture) (FTextureInfo *pTexInfo)
// -----------------+ // -----------------+
// SetTexture : The mipmap becomes the current texture source // SetTexture : The mipmap becomes the current texture source
// -----------------+ // -----------------+
EXPORT void HWRAPI(SetTexture) (FTextureInfo *pTexInfo) EXPORT void HWRAPI(SetTexture) (GLMipmap_t *pTexInfo)
{ {
if (!pTexInfo) if (!pTexInfo)
{ {
@ -1937,17 +1961,25 @@ EXPORT void HWRAPI(SetTexture) (FTextureInfo *pTexInfo)
} }
else else
{ {
FTextureInfo *newTex = calloc(1, sizeof (*newTex));
UpdateTexture(pTexInfo); UpdateTexture(pTexInfo);
pTexInfo->nextmipmap = NULL;
newTex->texture = pTexInfo;
newTex->downloaded = (UINT32)pTexInfo->downloaded;
newTex->width = (UINT32)pTexInfo->width;
newTex->height = (UINT32)pTexInfo->height;
newTex->format = (UINT32)pTexInfo->format;
// insertion at the tail // insertion at the tail
if (gl_cachetail) if (TexCacheTail)
{ {
gl_cachetail->nextmipmap = pTexInfo; newTex->prev = TexCacheTail;
gl_cachetail = pTexInfo; TexCacheTail->next = newTex;
TexCacheTail = newTex;
} }
else // initialization of the linked list else // initialization of the linked list
gl_cachetail = gl_cachehead = pTexInfo; TexCacheTail = TexCacheHead = newTex;
} }
} }
@ -3011,7 +3043,7 @@ EXPORT void HWRAPI(SetTransform) (FTransform *stransform)
EXPORT INT32 HWRAPI(GetTextureUsed) (void) EXPORT INT32 HWRAPI(GetTextureUsed) (void)
{ {
FTextureInfo *tmp = gl_cachehead; FTextureInfo *tmp = TexCacheHead;
INT32 res = 0; INT32 res = 0;
while (tmp) while (tmp)
@ -3028,7 +3060,7 @@ EXPORT INT32 HWRAPI(GetTextureUsed) (void)
// Add it up! // Add it up!
res += tmp->height*tmp->width*bpp; res += tmp->height*tmp->width*bpp;
tmp = tmp->nextmipmap; tmp = tmp->next;
} }
return res; return res;

View File

@ -90,7 +90,6 @@ void *hwSym(const char *funcName,void *handle)
GETFUNC(ReadRect); GETFUNC(ReadRect);
GETFUNC(GClipRect); GETFUNC(GClipRect);
GETFUNC(ClearMipMapCache); GETFUNC(ClearMipMapCache);
GETFUNC(ClearCacheList);
GETFUNC(SetSpecialState); GETFUNC(SetSpecialState);
GETFUNC(GetTextureUsed); GETFUNC(GetTextureUsed);
GETFUNC(DrawModel); GETFUNC(DrawModel);

View File

@ -1862,7 +1862,6 @@ void VID_StartupOpenGL(void)
HWD.pfnReadRect = hwSym("ReadRect",NULL); HWD.pfnReadRect = hwSym("ReadRect",NULL);
HWD.pfnGClipRect = hwSym("GClipRect",NULL); HWD.pfnGClipRect = hwSym("GClipRect",NULL);
HWD.pfnClearMipMapCache = hwSym("ClearMipMapCache",NULL); HWD.pfnClearMipMapCache = hwSym("ClearMipMapCache",NULL);
HWD.pfnClearCacheList = hwSym("ClearCacheList",NULL);
HWD.pfnSetSpecialState = hwSym("SetSpecialState",NULL); HWD.pfnSetSpecialState = hwSym("SetSpecialState",NULL);
HWD.pfnSetPalette = hwSym("SetPalette",NULL); HWD.pfnSetPalette = hwSym("SetPalette",NULL);
HWD.pfnGetTextureUsed = hwSym("GetTextureUsed",NULL); HWD.pfnGetTextureUsed = hwSym("GetTextureUsed",NULL);

View File

@ -1682,26 +1682,12 @@ void *W_CacheSoftwarePatchNumPwad(UINT16 wad, UINT16 lump, INT32 tag)
// read the lump in full // read the lump in full
W_ReadLumpHeaderPwad(wad, lump, lumpdata, 0, 0); W_ReadLumpHeaderPwad(wad, lump, lumpdata, 0, 0);
ptr = lumpdata;
#ifndef NO_PNG_LUMPS #ifndef NO_PNG_LUMPS
// lump is a png so convert it
if (Picture_IsLumpPNG((UINT8 *)lumpdata, len)) if (Picture_IsLumpPNG((UINT8 *)lumpdata, len))
{ ptr = Picture_PNGConvert((UINT8 *)lumpdata, PICFMT_DOOMPATCH, NULL, NULL, NULL, NULL, len, &len, 0);
size_t newlen;
void *converted = Picture_PNGConvert((UINT8 *)lumpdata, PICFMT_DOOMPATCH, NULL, NULL, NULL, NULL, len, &newlen, 0);
ptr = Z_Malloc(newlen, PU_STATIC, NULL);
M_Memcpy(ptr, converted, newlen);
Z_Free(converted);
len = newlen;
}
else // just copy it into the patch cache
#endif #endif
{
ptr = Z_Malloc(len, PU_STATIC, NULL);
M_Memcpy(ptr, lumpdata, len);
}
Z_Free(lumpdata);
dest = Z_Calloc(sizeof(patch_t), tag, &lumpcache[lump]); dest = Z_Calloc(sizeof(patch_t), tag, &lumpcache[lump]);
Patch_Create(ptr, len, dest); Patch_Create(ptr, len, dest);

View File

@ -111,7 +111,6 @@ static loadfunc_t hwdFuncTable[] = {
{"ReadRect@24", &hwdriver.pfnReadRect}, {"ReadRect@24", &hwdriver.pfnReadRect},
{"GClipRect@20", &hwdriver.pfnGClipRect}, {"GClipRect@20", &hwdriver.pfnGClipRect},
{"ClearMipMapCache@0", &hwdriver.pfnClearMipMapCache}, {"ClearMipMapCache@0", &hwdriver.pfnClearMipMapCache},
{"ClearCacheList@0", &hwdriver.pfnClearCacheList},
{"SetSpecialState@8", &hwdriver.pfnSetSpecialState}, {"SetSpecialState@8", &hwdriver.pfnSetSpecialState},
{"DrawModel@16", &hwdriver.pfnDrawModel}, {"DrawModel@16", &hwdriver.pfnDrawModel},
{"SetTransform@4", &hwdriver.pfnSetTransform}, {"SetTransform@4", &hwdriver.pfnSetTransform},
@ -145,7 +144,6 @@ static loadfunc_t hwdFuncTable[] = {
{"ReadRect", &hwdriver.pfnReadRect}, {"ReadRect", &hwdriver.pfnReadRect},
{"GClipRect", &hwdriver.pfnGClipRect}, {"GClipRect", &hwdriver.pfnGClipRect},
{"ClearMipMapCache", &hwdriver.pfnClearMipMapCache}, {"ClearMipMapCache", &hwdriver.pfnClearMipMapCache},
{"ClearCacheList", &hwdriver.pfnClearCacheList},
{"SetSpecialState", &hwdriver.pfnSetSpecialState}, {"SetSpecialState", &hwdriver.pfnSetSpecialState},
{"DrawModel", &hwdriver.pfnDrawModel}, {"DrawModel", &hwdriver.pfnDrawModel},
{"SetTransform", &hwdriver.pfnSetTransform}, {"SetTransform", &hwdriver.pfnSetTransform},

View File

@ -68,8 +68,7 @@ enum
PU_HWRCACHE_UNLOCKED = 102, // 'unlocked' PU_HWRCACHE memory: PU_HWRCACHE_UNLOCKED = 102, // 'unlocked' PU_HWRCACHE memory:
// 'second-level' cache for graphics // 'second-level' cache for graphics
// stored in hardware format and downloaded as needed // stored in hardware format and downloaded as needed
PU_HWRPATCHINFO_UNLOCKED = 103, // 'unlocked' PU_HWRPATCHINFO memory PU_HWRMODELTEXTURE_UNLOCKED = 103, // 'unlocked' PU_HWRMODELTEXTURE memory
PU_HWRMODELTEXTURE_UNLOCKED = 104, // 'unlocked' PU_HWRMODELTEXTURE memory
}; };
// //