Revisions for untitled paste

View the changes made to this paste.

unlisted ⁨1⁩ ⁨file⁩ 2023-05-07 11:11:20 UTC

sub_531C30.cpp

@@ -0,0 +1,154 @@

+#include <windows.h>
+#include <D3DX8.h>
+#include <ddraw.h>
+#include <d3d8.h>
+
+extern IDirect3DDevice8 *g_pD3DDevice8_8E4768;
+extern HWND g_hWnd;
+
+/**
+  * Try to fill up the video memory first with textures, then with surfaces.
+  * Based on how many of these could be created, return the maximum amount of VRAM available in MiB.
+**/
+DWORD sub_531C30(UnknownSLC2002GameObject *this)
+{
+  unsigned int numOfCreatedTextures; // edi
+  IDirect3DTexture8 **ppCurrentTexture; // esi
+  int colorDepthSizeReqMultiplier; // ebp
+  IDirect3DDevice8 *pDirect3DDevice8; // eax
+  HRESULT createResult; // eax MAPDST
+  DWORD usableVramBytes; // ebp
+  unsigned int i; // esi
+  IDirect3DTexture8 *pTextureToRelease; // eax
+  IDirectDrawSurface7 **ppCurrentSurface; // esi
+  DWORD redBitMask; // eax
+  DWORD greenBitMask; // ecx
+  DWORD blueBitMask; // edx
+  unsigned int numOfCreatedSurfaces; // edi
+  unsigned int j; // esi
+  IDirectDrawSurface7 *pSurfaceToRelease; // eax
+  DWORD usableVramMiB; // eax
+  D3DFORMAT d3dSurfaceFormat; // [esp+30h] [ebp-10A8h]
+  IDirectDraw7 *pDirectDraw7; // [esp+50h] [ebp-1088h] MAPDST BYREF
+  IDirectDraw *lpIDirectDraw; // [esp+54h] [ebp-1084h] BYREF
+  DWORD _unused; // [esp+58h] [ebp-1080h]
+  DDSURFACEDESC2 surfaceDescriptor; // [esp+5Ch] [ebp-107Ch] BYREF
+  IDirect3DTexture8 *dummyTextures[512]; // [esp+D8h] [ebp-1000h] BYREF
+  IDirectDrawSurface7 *dummySurfaces[512]; // [esp+8D8h] [ebp-800h] BYREF
+
+  numOfCreatedTextures = 0;
+  ppCurrentTexture = dummyTextures;
+  
+  // This can only be either D3DFMT_X8R8G8B8 or D3DFMT_R5G6B5, depending on whether 32-bit or 16-bit color depth was chosen in the game launcher dialog, respectively.
+  // D3DFMT_R5G6B5:     16-bit RGB pixel format with 5 bits for red, 6 bits for green, and 5 bits for blue.
+  // D3DFMT_X8R8G8B8:   32-bit RGB pixel format, where 8 bits are reserved for each color.
+  d3dSurfaceFormat = this[752];
+  
+  // 32-bit colors: x2, 16-bit colors: x1
+  colorDepthSizeReqMultiplier = (d3dSurfaceFormat != D3DFMT_R5G6B5) + 1;
+
+  // create the textures
+  do
+  {
+    pDirect3DDevice8 = g_pD3DDevice8_8E4768;
+    *ppCurrentTexture = NULL;
+
+    createResult = pDirect3DDevice8->CreateTexture(
+                     256,                             // width
+                     256,                             // height
+                     1,                               // levels
+                     D3DUSAGE_RENDERTARGET,           // usage
+                     d3dSurfaceFormat,                // format
+                     D3DPOOL_DEFAULT,                 // pool
+                     ppCurrentTexture);               // ppTexture
+    
+    if ( SUCCEEDED(createResult) )
+    {
+      ++numOfCreatedTextures;
+      ++ppCurrentTexture;
+    }
+  }
+  while ( numOfCreatedTextures <= 512 && SUCCEEDED(createResult) );
+
+  // each texture's size in bytes: 128K if 16-bit, 256K if 32-bit
+  if ( createResult == D3DERR_OUTOFVIDEOMEMORY && numOfCreatedTextures )
+    // Fun fact: the last multiplication was decompiled to x << 17 originally, which is equivalent to x * 0x20000 (131072, 128K)
+    usableVramBytes = (numOfCreatedTextures * colorDepthSizeReqMultiplier) * 0x20000;
+  else
+    usableVramBytes = 0;
+
+  // clean up the textures
+  for ( i = 0; i < numOfCreatedTextures; ++i )
+  {
+    pTextureToRelease = dummyTextures[i];
+    if ( pTextureToRelease )
+      pTextureToRelease->Release();
+    dummyTextures[i] = NULL;
+  }
+
+  // first get a generic IDirectDraw 1.0 interface, then from that retrieve a newer, version 7.0 one
+  if ( FAILED(DirectDrawCreateEx(NULL, (void**)&lpIDirectDraw, IID_IDirectDraw7, NULL))
+      || FAILED(lpIDirectDraw->QueryInterface(IID_IDirectDraw7, (void **)&pDirectDraw7)) )
+  {
+    return 0;
+  }
+
+  // describe what kind of surfaces to create
+  pDirectDraw7->SetCooperativeLevel(g_hWnd, DDSCL_NORMAL);
+  memset(&surfaceDescriptor, 0, sizeof(surfaceDescriptor));
+  surfaceDescriptor.dwWidth = 256;
+  surfaceDescriptor.dwHeight = 256;
+  surfaceDescriptor.dwSize = 124;
+  surfaceDescriptor.dwFlags = DDSD_PIXELFORMAT|DDSD_WIDTH|DDSD_HEIGHT|DDSD_CAPS;
+  surfaceDescriptor.ddsCaps.dwCaps = DDSCAPS_VIDEOMEMORY|DDSCAPS_OFFSCREENPLAIN;
+
+  memset(&surfaceDescriptor.ddpfPixelFormat, 0, sizeof(surfaceDescriptor.ddpfPixelFormat));
+  redBitMask = this[389]; // seems to always be 0xF800
+  greenBitMask = this[390]; // seems to always be 0x7E0
+  blueBitMask = this[391]; // seems to always be 0x1F
+  surfaceDescriptor.ddpfPixelFormat.dwSize = 32;
+  surfaceDescriptor.ddpfPixelFormat.dwFlags = DDPF_RGB;
+  surfaceDescriptor.ddpfPixelFormat.dwRGBBitCount = 16;
+  surfaceDescriptor.ddpfPixelFormat.dwRBitMask = redBitMask;
+  surfaceDescriptor.ddpfPixelFormat.dwGBitMask = greenBitMask;
+  surfaceDescriptor.ddpfPixelFormat.dwBBitMask = blueBitMask;
+  surfaceDescriptor.ddpfPixelFormat.dwRGBAlphaBitMask = 0x00000000;
+
+  numOfCreatedSurfaces = 0;
+  ppCurrentSurface = &dummySurfaces[0];
+
+  // create the surfaces
+  do
+  {
+    *ppCurrentSurface = NULL;
+    createResult = pDirectDraw7->CreateSurface(&surfaceDescriptor, ppCurrentSurface, NULL);
+    if ( !createResult )
+    {
+      ++numOfCreatedSurfaces;
+      ++ppCurrentSurface;
+    }
+  }
+  while ( numOfCreatedSurfaces <= 512 && SUCCEEDED(createResult) );
+
+  // each surface's size in bytes: always 128K, regardless of color depth set in launcher
+  if ( createResult == D3DERR_OUTOFVIDEOMEMORY && numOfCreatedSurfaces
+    && (numOfCreatedSurfaces * 0x20000) < usableVramBytes )
+      // if less surfaces could be created than textures, reduce the usable/available VRAM size accordingly
+      usableVramBytes = numOfCreatedSurfaces * 0x20000;
+
+  // clean up the surfaces
+  for ( j = 0; j < numOfCreatedSurfaces; ++j )
+  {
+    pSurfaceToRelease = dummySurfaces[j];
+    if ( pSurfaceToRelease )
+      pSurfaceToRelease->Release();
+    dummySurfaces[j] = NULL;
+  }
+
+  pDirectDraw7->Release();
+
+  // 1 byte = 0.00000095367432 MiB; this basically converts usableVramBytes from bytes to Mibibytes.
+  // The long conversion uses MSVC's _ftol behind the scenes.
+  usableVramMiB = (long)((double)usableVramBytes * 0.00000095367432);
+  return usableVramMiB;
+}
\ No newline at end of file