Files
Revelations/Minecraft.Client/Windows64/Windows64_Minecraft.cpp
T
itsRevela 2c23e3e54c wip: flip mode resize buffers experiment (blocked by deferred context IntRefs)
Experimental branch that tried to enable screen tearing by switching the swap chain from DXGI_SWAP_EFFECT_DISCARD (bitblt) to DXGI_SWAP_EFFECT_FLIP_DISCARD with the ALLOW_TEARING flag. Tearing in flip mode requires ResizeBuffers on window resize because flip swap chains take exclusive ownership of the HWND and cannot be destroyed-and-recreated like bitblt ones.

ResizeBuffers fails with DXGI_ERROR_INVALID_CALL (0x887A0001) every time. Diagnosis path got us to the authoritative cause via the DXGI debug layer's info queue and ID3D11Debug::ReportLiveDeviceObjects: both physical backbuffers of the flip chain have an internal reference count of 5 (D3D11 IntRef, not public COM refcount). DXGI's outstanding-references check looks at IntRef, which is why probing public refcount always showed 2 and nothing we released dropped it.

The internal refs come from the 4J Renderer library's use of a deferred context. Renderer::InitialiseContext calls ID3D11Device::CreateDeferredContext and records commands into it via Renderer::Context (stored in thread-local storage). Commands that reference the backbuffer or an RTV wrapping it pin IntRefs on the backbuffer texture until the command list is Finished and then Released. The Renderer library owns that command list and we have no handle to it, so we cannot drop those refs from the outside without reverse engineering significantly more of the 4J library.

This commit preserves the instrumentation and the failed flip mode experiment so we can return to it later if a cleaner approach becomes available. Retained in this file:
- DXGI_FEATURE_PRESENT_ALLOW_TEARING probe and g_bTearingSupported global
- FLIP_DISCARD swap chain config with ALLOW_TEARING flag
- ResizeBuffers call path in ResizeD3D with fallback recovery for when it fails
- Dedicated file logger (FlipTestLog) writing to flip_test.log
- D3D11 and DXGI info queue capture helpers
- ID3D11Debug / IDXGIDebug ReportLiveObjects wiring
- Granular refcount probes throughout the resize cleanup chain
- GPU idle wait via ID3D11Query fence

Not a fix. The next iteration goes back to bitblt and tries exclusive fullscreen for tearing instead.
2026-04-11 05:00:04 -05:00

2703 lines
92 KiB
C++

// Minecraft.cpp : Defines the entry point for the application.
//
#include "stdafx.h"
// FLIP-MODE TEST: headers for IDXGIFactory5 (tearing support probe) and
// ID3D11InfoQueue (debug layer message capture).
#include <dxgi1_5.h>
#include <d3d11sdklayers.h>
#include <dxgidebug.h>
#include <assert.h>
#include <iostream>
#include <ShellScalingApi.h>
#include <shellapi.h>
#include "GameConfig/Minecraft.spa.h"
#include "../MinecraftServer.h"
#include "../LocalPlayer.h"
#include "../../Minecraft.World/ItemInstance.h"
#include "../../Minecraft.World/MapItem.h"
#include "../../Minecraft.World/Recipes.h"
#include "../../Minecraft.World/Recipy.h"
#include "../../Minecraft.World/Language.h"
#include "../../Minecraft.World/StringHelpers.h"
#include "../../Minecraft.World/AABB.h"
#include "../../Minecraft.World/Vec3.h"
#include "../../Minecraft.World/Level.h"
#include "../../Minecraft.World/net.minecraft.world.level.tile.h"
#include "../ClientConnection.h"
#include "../Minecraft.h"
#include "../ChatScreen.h"
#include "KeyboardMouseInput.h"
#include "../User.h"
#include "../../Minecraft.World/Socket.h"
#include "../../Minecraft.World/ThreadName.h"
#include "../../Minecraft.Client/StatsCounter.h"
#include "../ConnectScreen.h"
//#include "Social/SocialManager.h"
//#include "Leaderboards/LeaderboardManager.h"
//#include "XUI/XUI_Scene_Container.h"
//#include "NetworkManager.h"
#include "../../Minecraft.Client/Tesselator.h"
#include "../../Minecraft.Client/Options.h"
#include "../Gui.h"
#include "Sentient/SentientManager.h"
#include "../../Minecraft.World/IntCache.h"
#include "../Textures.h"
#include "../Settings.h"
#include "Resource.h"
#include "../../Minecraft.World/compression.h"
#include "../../Minecraft.World/OldChunkStorage.h"
#include "Common/PostProcesser.h"
#include "../GameRenderer.h"
#include "Network/WinsockNetLayer.h"
#include "Windows64_Xuid.h"
#include "Common/UI/UI.h"
#include "stb_image_write.h"
// Forward-declare the internal Renderer class and its global instance from 4J_Render_PC_d.lib.
// C4JRender (RenderManager) is a stateless wrapper — all D3D state lives in InternalRenderManager.
class Renderer;
extern Renderer InternalRenderManager;
#include "Xbox/Resource.h"
#ifdef _MSC_VER
#pragma comment(lib, "legacy_stdio_definitions.lib")
#endif
HINSTANCE hMyInst;
LRESULT CALLBACK DlgProc(HWND hWndDlg, UINT Msg, WPARAM wParam, LPARAM lParam);
char chGlobalText[256];
uint16_t ui16GlobalText[256];
#define THEME_NAME "584111F70AAAAAAA"
#define THEME_FILESIZE 2797568
//#define THREE_MB 3145728 // minimum save size (checking for this on a selected device)
//#define FIVE_MB 5242880 // minimum save size (checking for this on a selected device)
//#define FIFTY_TWO_MB (1024*1024*52) // Maximum TCR space required for a save (checking for this on a selected device)
#define FIFTY_ONE_MB (1000000*51) // Maximum TCR space required for a save is 52MB (checking for this on a selected device)
//#define PROFILE_VERSION 3 // new version for the interim bug fix 166 TU
#define NUM_PROFILE_VALUES 5
#define NUM_PROFILE_SETTINGS 4
DWORD dwProfileSettingsA[NUM_PROFILE_VALUES]=
{
#ifdef _XBOX
XPROFILE_OPTION_CONTROLLER_VIBRATION,
XPROFILE_GAMER_YAXIS_INVERSION,
XPROFILE_GAMER_CONTROL_SENSITIVITY,
XPROFILE_GAMER_ACTION_MOVEMENT_CONTROL,
XPROFILE_TITLE_SPECIFIC1,
#else
0,0,0,0,0
#endif
};
//-------------------------------------------------------------------------------------
// Time Since fAppTime is a float, we need to keep the quadword app time
// as a LARGE_INTEGER so that we don't lose precision after running
// for a long time.
//-------------------------------------------------------------------------------------
BOOL g_bWidescreen = TRUE;
// Screen resolution — auto-detected from the monitor at startup.
// The 3D world renders at native resolution; Flash UI is 16:9-fitted and centered
// within each viewport (pillarboxed on ultrawide, letterboxed on tall displays).
// ApplyScreenMode() can still override these for debug/test resolutions via launch args.
int g_iScreenWidth = 1920;
int g_iScreenHeight = 1080;
// Real window dimensions — updated on every WM_SIZE so the 3D perspective
// always matches the current window, even after a resize.
int g_rScreenWidth = 1920;
int g_rScreenHeight = 1080;
static bool f3ComboUsed = false;
float g_iAspectRatio = static_cast<float>(g_iScreenWidth) / g_iScreenHeight;
static bool g_bResizeReady = false;
char g_Win64Username[17] = { 0 };
wchar_t g_Win64UsernameW[17] = { 0 };
// Fullscreen toggle state
static bool g_isFullscreen = false;
static WINDOWPLACEMENT g_wpPrev = { sizeof(g_wpPrev) };
struct Win64LaunchOptions
{
int screenMode;
bool fullscreen;
};
static void CopyWideArgToAnsi(LPCWSTR source, char* dest, size_t destSize)
{
if (destSize == 0)
return;
dest[0] = 0;
if (source == nullptr)
return;
WideCharToMultiByte(CP_ACP, 0, source, -1, dest, static_cast<int>(destSize), nullptr, nullptr);
dest[destSize - 1] = 0;
}
// ---------- Persistent options (options.txt next to exe) ----------
static void GetOptionsFilePath(char *out, size_t outSize)
{
GetModuleFileNameA(nullptr, out, static_cast<DWORD>(outSize));
char *p = strrchr(out, '\\');
if (p) *(p + 1) = '\0';
strncat_s(out, outSize, "options.txt", _TRUNCATE);
}
static void SaveFullscreenOption(bool fullscreen)
{
char path[MAX_PATH];
GetOptionsFilePath(path, sizeof(path));
FILE *f = nullptr;
if (fopen_s(&f, path, "w") == 0 && f)
{
fprintf(f, "fullscreen=%d\n", fullscreen ? 1 : 0);
fclose(f);
}
}
static bool LoadFullscreenOption()
{
char path[MAX_PATH];
GetOptionsFilePath(path, sizeof(path));
FILE *f = nullptr;
if (fopen_s(&f, path, "r") == 0 && f)
{
char line[256];
while (fgets(line, sizeof(line), f))
{
int val = 0;
if (sscanf_s(line, "fullscreen=%d", &val) == 1)
{
fclose(f);
return val != 0;
}
}
fclose(f);
}
return false;
}
// ------------------------------------------------------------------
static void ApplyScreenMode(int screenMode)
{
switch (screenMode)
{
case 1:
g_iScreenWidth = 1280;
g_iScreenHeight = 720;
break;
case 2:
g_iScreenWidth = 640;
g_iScreenHeight = 480;
break;
case 3:
g_iScreenWidth = 720;
g_iScreenHeight = 408;
break;
default:
break;
}
}
static Win64LaunchOptions ParseLaunchOptions()
{
Win64LaunchOptions options = {};
options.screenMode = 0;
g_Win64MultiplayerJoin = false;
g_Win64MultiplayerPort = WIN64_NET_DEFAULT_PORT;
int argc = 0;
LPWSTR* argv = CommandLineToArgvW(GetCommandLineW(), &argc);
if (argv == nullptr)
return options;
if (argc > 1 && lstrlenW(argv[1]) == 1)
{
if (argv[1][0] >= L'1' && argv[1][0] <= L'3')
options.screenMode = argv[1][0] - L'0';
}
for (int i = 1; i < argc; ++i)
{
if (_wcsicmp(argv[i], L"-name") == 0 && (i + 1) < argc)
{
CopyWideArgToAnsi(argv[++i], g_Win64Username, sizeof(g_Win64Username));
}
else if (_wcsicmp(argv[i], L"-ip") == 0 && (i + 1) < argc)
{
char ipBuf[256];
CopyWideArgToAnsi(argv[++i], ipBuf, sizeof(ipBuf));
strncpy_s(g_Win64MultiplayerIP, sizeof(g_Win64MultiplayerIP), ipBuf, _TRUNCATE);
g_Win64MultiplayerJoin = true;
}
else if (_wcsicmp(argv[i], L"-port") == 0 && (i + 1) < argc)
{
wchar_t* endPtr = nullptr;
const long port = wcstol(argv[++i], &endPtr, 10);
if (endPtr != argv[i] && *endPtr == 0 && port > 0 && port <= 65535)
{
g_Win64MultiplayerPort = static_cast<int>(port);
}
}
else if (_wcsicmp(argv[i], L"-fullscreen") == 0)
options.fullscreen = true;
}
LocalFree(argv);
return options;
}
void DefineActions(void)
{
// The app needs to define the actions required, and the possible mappings for these
// Split into Menu actions, and in-game actions
InputManager.SetGameJoypadMaps(MAP_STYLE_0,ACTION_MENU_A, _360_JOY_BUTTON_A);
InputManager.SetGameJoypadMaps(MAP_STYLE_0,ACTION_MENU_B, _360_JOY_BUTTON_B);
InputManager.SetGameJoypadMaps(MAP_STYLE_0,ACTION_MENU_X, _360_JOY_BUTTON_X);
InputManager.SetGameJoypadMaps(MAP_STYLE_0,ACTION_MENU_Y, _360_JOY_BUTTON_Y);
InputManager.SetGameJoypadMaps(MAP_STYLE_0,ACTION_MENU_OK, _360_JOY_BUTTON_A);
InputManager.SetGameJoypadMaps(MAP_STYLE_0,ACTION_MENU_CANCEL, _360_JOY_BUTTON_B);
InputManager.SetGameJoypadMaps(MAP_STYLE_0,ACTION_MENU_UP, _360_JOY_BUTTON_DPAD_UP | _360_JOY_BUTTON_LSTICK_UP);
InputManager.SetGameJoypadMaps(MAP_STYLE_0,ACTION_MENU_DOWN, _360_JOY_BUTTON_DPAD_DOWN | _360_JOY_BUTTON_LSTICK_DOWN);
InputManager.SetGameJoypadMaps(MAP_STYLE_0,ACTION_MENU_LEFT, _360_JOY_BUTTON_DPAD_LEFT | _360_JOY_BUTTON_LSTICK_LEFT);
InputManager.SetGameJoypadMaps(MAP_STYLE_0,ACTION_MENU_RIGHT, _360_JOY_BUTTON_DPAD_RIGHT | _360_JOY_BUTTON_LSTICK_RIGHT);
InputManager.SetGameJoypadMaps(MAP_STYLE_0,ACTION_MENU_PAGEUP, _360_JOY_BUTTON_LT);
InputManager.SetGameJoypadMaps(MAP_STYLE_0,ACTION_MENU_PAGEDOWN, _360_JOY_BUTTON_RT);
InputManager.SetGameJoypadMaps(MAP_STYLE_0,ACTION_MENU_RIGHT_SCROLL, _360_JOY_BUTTON_RB);
InputManager.SetGameJoypadMaps(MAP_STYLE_0,ACTION_MENU_LEFT_SCROLL, _360_JOY_BUTTON_LB);
InputManager.SetGameJoypadMaps(MAP_STYLE_0,ACTION_MENU_PAUSEMENU, _360_JOY_BUTTON_START);
InputManager.SetGameJoypadMaps(MAP_STYLE_0,ACTION_MENU_STICK_PRESS, _360_JOY_BUTTON_LTHUMB);
InputManager.SetGameJoypadMaps(MAP_STYLE_0,ACTION_MENU_OTHER_STICK_PRESS, _360_JOY_BUTTON_RTHUMB);
InputManager.SetGameJoypadMaps(MAP_STYLE_0,ACTION_MENU_OTHER_STICK_UP, _360_JOY_BUTTON_RSTICK_UP);
InputManager.SetGameJoypadMaps(MAP_STYLE_0,ACTION_MENU_OTHER_STICK_DOWN, _360_JOY_BUTTON_RSTICK_DOWN);
InputManager.SetGameJoypadMaps(MAP_STYLE_0,ACTION_MENU_OTHER_STICK_LEFT, _360_JOY_BUTTON_RSTICK_LEFT);
InputManager.SetGameJoypadMaps(MAP_STYLE_0,ACTION_MENU_OTHER_STICK_RIGHT, _360_JOY_BUTTON_RSTICK_RIGHT);
InputManager.SetGameJoypadMaps(MAP_STYLE_0,MINECRAFT_ACTION_JUMP, _360_JOY_BUTTON_A);
InputManager.SetGameJoypadMaps(MAP_STYLE_0,MINECRAFT_ACTION_FORWARD, _360_JOY_BUTTON_LSTICK_UP);
InputManager.SetGameJoypadMaps(MAP_STYLE_0,MINECRAFT_ACTION_BACKWARD, _360_JOY_BUTTON_LSTICK_DOWN);
InputManager.SetGameJoypadMaps(MAP_STYLE_0,MINECRAFT_ACTION_LEFT, _360_JOY_BUTTON_LSTICK_LEFT);
InputManager.SetGameJoypadMaps(MAP_STYLE_0,MINECRAFT_ACTION_RIGHT, _360_JOY_BUTTON_LSTICK_RIGHT);
InputManager.SetGameJoypadMaps(MAP_STYLE_0,MINECRAFT_ACTION_LOOK_LEFT, _360_JOY_BUTTON_RSTICK_LEFT);
InputManager.SetGameJoypadMaps(MAP_STYLE_0,MINECRAFT_ACTION_LOOK_RIGHT, _360_JOY_BUTTON_RSTICK_RIGHT);
InputManager.SetGameJoypadMaps(MAP_STYLE_0,MINECRAFT_ACTION_LOOK_UP, _360_JOY_BUTTON_RSTICK_UP);
InputManager.SetGameJoypadMaps(MAP_STYLE_0,MINECRAFT_ACTION_LOOK_DOWN, _360_JOY_BUTTON_RSTICK_DOWN);
InputManager.SetGameJoypadMaps(MAP_STYLE_0,MINECRAFT_ACTION_USE, _360_JOY_BUTTON_LT);
InputManager.SetGameJoypadMaps(MAP_STYLE_0,MINECRAFT_ACTION_ACTION, _360_JOY_BUTTON_RT);
InputManager.SetGameJoypadMaps(MAP_STYLE_0,MINECRAFT_ACTION_RIGHT_SCROLL, _360_JOY_BUTTON_RB);
InputManager.SetGameJoypadMaps(MAP_STYLE_0,MINECRAFT_ACTION_LEFT_SCROLL, _360_JOY_BUTTON_LB);
InputManager.SetGameJoypadMaps(MAP_STYLE_0,MINECRAFT_ACTION_INVENTORY, _360_JOY_BUTTON_Y);
InputManager.SetGameJoypadMaps(MAP_STYLE_0,MINECRAFT_ACTION_PAUSEMENU, _360_JOY_BUTTON_START);
InputManager.SetGameJoypadMaps(MAP_STYLE_0,MINECRAFT_ACTION_DROP, _360_JOY_BUTTON_B);
InputManager.SetGameJoypadMaps(MAP_STYLE_0,MINECRAFT_ACTION_SNEAK_TOGGLE, _360_JOY_BUTTON_RTHUMB);
InputManager.SetGameJoypadMaps(MAP_STYLE_0,MINECRAFT_ACTION_CRAFTING, _360_JOY_BUTTON_X);
InputManager.SetGameJoypadMaps(MAP_STYLE_0,MINECRAFT_ACTION_RENDER_THIRD_PERSON, _360_JOY_BUTTON_LTHUMB);
InputManager.SetGameJoypadMaps(MAP_STYLE_0,MINECRAFT_ACTION_GAME_INFO, _360_JOY_BUTTON_BACK);
InputManager.SetGameJoypadMaps(MAP_STYLE_0,MINECRAFT_ACTION_DPAD_LEFT, _360_JOY_BUTTON_DPAD_LEFT);
InputManager.SetGameJoypadMaps(MAP_STYLE_0,MINECRAFT_ACTION_DPAD_RIGHT, _360_JOY_BUTTON_DPAD_RIGHT);
InputManager.SetGameJoypadMaps(MAP_STYLE_0,MINECRAFT_ACTION_DPAD_UP, _360_JOY_BUTTON_DPAD_UP);
InputManager.SetGameJoypadMaps(MAP_STYLE_0,MINECRAFT_ACTION_DPAD_DOWN, _360_JOY_BUTTON_DPAD_DOWN);
InputManager.SetGameJoypadMaps(MAP_STYLE_1,ACTION_MENU_A, _360_JOY_BUTTON_A);
InputManager.SetGameJoypadMaps(MAP_STYLE_1,ACTION_MENU_B, _360_JOY_BUTTON_B);
InputManager.SetGameJoypadMaps(MAP_STYLE_1,ACTION_MENU_X, _360_JOY_BUTTON_X);
InputManager.SetGameJoypadMaps(MAP_STYLE_1,ACTION_MENU_Y, _360_JOY_BUTTON_Y);
InputManager.SetGameJoypadMaps(MAP_STYLE_1,ACTION_MENU_OK, _360_JOY_BUTTON_A);
InputManager.SetGameJoypadMaps(MAP_STYLE_1,ACTION_MENU_CANCEL, _360_JOY_BUTTON_B);
InputManager.SetGameJoypadMaps(MAP_STYLE_1,ACTION_MENU_UP, _360_JOY_BUTTON_DPAD_UP | _360_JOY_BUTTON_LSTICK_UP);
InputManager.SetGameJoypadMaps(MAP_STYLE_1,ACTION_MENU_DOWN, _360_JOY_BUTTON_DPAD_DOWN | _360_JOY_BUTTON_LSTICK_DOWN);
InputManager.SetGameJoypadMaps(MAP_STYLE_1,ACTION_MENU_LEFT, _360_JOY_BUTTON_DPAD_LEFT | _360_JOY_BUTTON_LSTICK_LEFT);
InputManager.SetGameJoypadMaps(MAP_STYLE_1,ACTION_MENU_RIGHT, _360_JOY_BUTTON_DPAD_RIGHT | _360_JOY_BUTTON_LSTICK_RIGHT);
InputManager.SetGameJoypadMaps(MAP_STYLE_1,ACTION_MENU_PAGEUP, _360_JOY_BUTTON_LB);
InputManager.SetGameJoypadMaps(MAP_STYLE_1,ACTION_MENU_PAGEDOWN, _360_JOY_BUTTON_RT);
InputManager.SetGameJoypadMaps(MAP_STYLE_1,ACTION_MENU_RIGHT_SCROLL, _360_JOY_BUTTON_RB);
InputManager.SetGameJoypadMaps(MAP_STYLE_1,ACTION_MENU_LEFT_SCROLL, _360_JOY_BUTTON_LB);
InputManager.SetGameJoypadMaps(MAP_STYLE_1,ACTION_MENU_PAUSEMENU, _360_JOY_BUTTON_START);
InputManager.SetGameJoypadMaps(MAP_STYLE_1,ACTION_MENU_STICK_PRESS, _360_JOY_BUTTON_LTHUMB);
InputManager.SetGameJoypadMaps(MAP_STYLE_1,ACTION_MENU_OTHER_STICK_PRESS, _360_JOY_BUTTON_RTHUMB);
InputManager.SetGameJoypadMaps(MAP_STYLE_1,ACTION_MENU_OTHER_STICK_UP, _360_JOY_BUTTON_RSTICK_UP);
InputManager.SetGameJoypadMaps(MAP_STYLE_1,ACTION_MENU_OTHER_STICK_DOWN, _360_JOY_BUTTON_RSTICK_DOWN);
InputManager.SetGameJoypadMaps(MAP_STYLE_1,ACTION_MENU_OTHER_STICK_LEFT, _360_JOY_BUTTON_RSTICK_LEFT);
InputManager.SetGameJoypadMaps(MAP_STYLE_1,ACTION_MENU_OTHER_STICK_RIGHT, _360_JOY_BUTTON_RSTICK_RIGHT);
InputManager.SetGameJoypadMaps(MAP_STYLE_1,MINECRAFT_ACTION_JUMP, _360_JOY_BUTTON_RB);
InputManager.SetGameJoypadMaps(MAP_STYLE_1,MINECRAFT_ACTION_FORWARD, _360_JOY_BUTTON_LSTICK_UP);
InputManager.SetGameJoypadMaps(MAP_STYLE_1,MINECRAFT_ACTION_BACKWARD, _360_JOY_BUTTON_LSTICK_DOWN);
InputManager.SetGameJoypadMaps(MAP_STYLE_1,MINECRAFT_ACTION_LEFT, _360_JOY_BUTTON_LSTICK_LEFT);
InputManager.SetGameJoypadMaps(MAP_STYLE_1,MINECRAFT_ACTION_RIGHT, _360_JOY_BUTTON_LSTICK_RIGHT);
InputManager.SetGameJoypadMaps(MAP_STYLE_1,MINECRAFT_ACTION_LOOK_LEFT, _360_JOY_BUTTON_RSTICK_LEFT);
InputManager.SetGameJoypadMaps(MAP_STYLE_1,MINECRAFT_ACTION_LOOK_RIGHT, _360_JOY_BUTTON_RSTICK_RIGHT);
InputManager.SetGameJoypadMaps(MAP_STYLE_1,MINECRAFT_ACTION_LOOK_UP, _360_JOY_BUTTON_RSTICK_UP);
InputManager.SetGameJoypadMaps(MAP_STYLE_1,MINECRAFT_ACTION_LOOK_DOWN, _360_JOY_BUTTON_RSTICK_DOWN);
InputManager.SetGameJoypadMaps(MAP_STYLE_1,MINECRAFT_ACTION_USE, _360_JOY_BUTTON_RT);
InputManager.SetGameJoypadMaps(MAP_STYLE_1,MINECRAFT_ACTION_ACTION, _360_JOY_BUTTON_LT);
InputManager.SetGameJoypadMaps(MAP_STYLE_1,MINECRAFT_ACTION_RIGHT_SCROLL, _360_JOY_BUTTON_DPAD_RIGHT);
InputManager.SetGameJoypadMaps(MAP_STYLE_1,MINECRAFT_ACTION_LEFT_SCROLL, _360_JOY_BUTTON_DPAD_LEFT);
InputManager.SetGameJoypadMaps(MAP_STYLE_1,MINECRAFT_ACTION_INVENTORY, _360_JOY_BUTTON_Y);
InputManager.SetGameJoypadMaps(MAP_STYLE_1,MINECRAFT_ACTION_PAUSEMENU, _360_JOY_BUTTON_START);
InputManager.SetGameJoypadMaps(MAP_STYLE_1,MINECRAFT_ACTION_DROP, _360_JOY_BUTTON_B);
InputManager.SetGameJoypadMaps(MAP_STYLE_1,MINECRAFT_ACTION_SNEAK_TOGGLE, _360_JOY_BUTTON_LTHUMB);
InputManager.SetGameJoypadMaps(MAP_STYLE_1,MINECRAFT_ACTION_CRAFTING, _360_JOY_BUTTON_X);
InputManager.SetGameJoypadMaps(MAP_STYLE_1,MINECRAFT_ACTION_RENDER_THIRD_PERSON, _360_JOY_BUTTON_RTHUMB);
InputManager.SetGameJoypadMaps(MAP_STYLE_1,MINECRAFT_ACTION_GAME_INFO, _360_JOY_BUTTON_BACK);
InputManager.SetGameJoypadMaps(MAP_STYLE_1,MINECRAFT_ACTION_DPAD_LEFT, _360_JOY_BUTTON_DPAD_LEFT);
InputManager.SetGameJoypadMaps(MAP_STYLE_1,MINECRAFT_ACTION_DPAD_RIGHT, _360_JOY_BUTTON_DPAD_RIGHT);
InputManager.SetGameJoypadMaps(MAP_STYLE_1,MINECRAFT_ACTION_DPAD_UP, _360_JOY_BUTTON_DPAD_UP);
InputManager.SetGameJoypadMaps(MAP_STYLE_1,MINECRAFT_ACTION_DPAD_DOWN, _360_JOY_BUTTON_DPAD_DOWN);
InputManager.SetGameJoypadMaps(MAP_STYLE_2,ACTION_MENU_A, _360_JOY_BUTTON_A);
InputManager.SetGameJoypadMaps(MAP_STYLE_2,ACTION_MENU_B, _360_JOY_BUTTON_B);
InputManager.SetGameJoypadMaps(MAP_STYLE_2,ACTION_MENU_X, _360_JOY_BUTTON_X);
InputManager.SetGameJoypadMaps(MAP_STYLE_2,ACTION_MENU_Y, _360_JOY_BUTTON_Y);
InputManager.SetGameJoypadMaps(MAP_STYLE_2,ACTION_MENU_OK, _360_JOY_BUTTON_A);
InputManager.SetGameJoypadMaps(MAP_STYLE_2,ACTION_MENU_CANCEL, _360_JOY_BUTTON_B);
InputManager.SetGameJoypadMaps(MAP_STYLE_2,ACTION_MENU_UP, _360_JOY_BUTTON_DPAD_UP | _360_JOY_BUTTON_LSTICK_UP);
InputManager.SetGameJoypadMaps(MAP_STYLE_2,ACTION_MENU_DOWN, _360_JOY_BUTTON_DPAD_DOWN | _360_JOY_BUTTON_LSTICK_DOWN);
InputManager.SetGameJoypadMaps(MAP_STYLE_2,ACTION_MENU_LEFT, _360_JOY_BUTTON_DPAD_LEFT | _360_JOY_BUTTON_LSTICK_LEFT);
InputManager.SetGameJoypadMaps(MAP_STYLE_2,ACTION_MENU_RIGHT, _360_JOY_BUTTON_DPAD_RIGHT | _360_JOY_BUTTON_LSTICK_RIGHT);
InputManager.SetGameJoypadMaps(MAP_STYLE_2,ACTION_MENU_PAGEUP, _360_JOY_BUTTON_DPAD_UP | _360_JOY_BUTTON_LB);
InputManager.SetGameJoypadMaps(MAP_STYLE_2,ACTION_MENU_PAGEDOWN, _360_JOY_BUTTON_RT);
InputManager.SetGameJoypadMaps(MAP_STYLE_2,ACTION_MENU_RIGHT_SCROLL, _360_JOY_BUTTON_RB);
InputManager.SetGameJoypadMaps(MAP_STYLE_2,ACTION_MENU_LEFT_SCROLL, _360_JOY_BUTTON_LB);
InputManager.SetGameJoypadMaps(MAP_STYLE_2,MINECRAFT_ACTION_JUMP, _360_JOY_BUTTON_LT);
InputManager.SetGameJoypadMaps(MAP_STYLE_2,MINECRAFT_ACTION_FORWARD, _360_JOY_BUTTON_LSTICK_UP);
InputManager.SetGameJoypadMaps(MAP_STYLE_2,MINECRAFT_ACTION_BACKWARD, _360_JOY_BUTTON_LSTICK_DOWN);
InputManager.SetGameJoypadMaps(MAP_STYLE_2,MINECRAFT_ACTION_LEFT, _360_JOY_BUTTON_LSTICK_LEFT);
InputManager.SetGameJoypadMaps(MAP_STYLE_2,MINECRAFT_ACTION_RIGHT, _360_JOY_BUTTON_LSTICK_RIGHT);
InputManager.SetGameJoypadMaps(MAP_STYLE_2,MINECRAFT_ACTION_LOOK_LEFT, _360_JOY_BUTTON_RSTICK_LEFT);
InputManager.SetGameJoypadMaps(MAP_STYLE_2,MINECRAFT_ACTION_LOOK_RIGHT, _360_JOY_BUTTON_RSTICK_RIGHT);
InputManager.SetGameJoypadMaps(MAP_STYLE_2,MINECRAFT_ACTION_LOOK_UP, _360_JOY_BUTTON_RSTICK_UP);
InputManager.SetGameJoypadMaps(MAP_STYLE_2,MINECRAFT_ACTION_LOOK_DOWN, _360_JOY_BUTTON_RSTICK_DOWN);
InputManager.SetGameJoypadMaps(MAP_STYLE_2,MINECRAFT_ACTION_USE, _360_JOY_BUTTON_RT);
InputManager.SetGameJoypadMaps(MAP_STYLE_2,MINECRAFT_ACTION_ACTION, _360_JOY_BUTTON_A);
InputManager.SetGameJoypadMaps(MAP_STYLE_2,MINECRAFT_ACTION_RIGHT_SCROLL, _360_JOY_BUTTON_DPAD_RIGHT);
InputManager.SetGameJoypadMaps(MAP_STYLE_2,MINECRAFT_ACTION_LEFT_SCROLL, _360_JOY_BUTTON_DPAD_LEFT);
InputManager.SetGameJoypadMaps(MAP_STYLE_2,MINECRAFT_ACTION_INVENTORY, _360_JOY_BUTTON_Y);
InputManager.SetGameJoypadMaps(MAP_STYLE_2,MINECRAFT_ACTION_PAUSEMENU, _360_JOY_BUTTON_START);
InputManager.SetGameJoypadMaps(MAP_STYLE_2,MINECRAFT_ACTION_DROP, _360_JOY_BUTTON_B);
InputManager.SetGameJoypadMaps(MAP_STYLE_2,MINECRAFT_ACTION_SNEAK_TOGGLE, _360_JOY_BUTTON_LB);
InputManager.SetGameJoypadMaps(MAP_STYLE_2,MINECRAFT_ACTION_CRAFTING, _360_JOY_BUTTON_X);
InputManager.SetGameJoypadMaps(MAP_STYLE_2,MINECRAFT_ACTION_RENDER_THIRD_PERSON, _360_JOY_BUTTON_LTHUMB);
InputManager.SetGameJoypadMaps(MAP_STYLE_2,MINECRAFT_ACTION_GAME_INFO, _360_JOY_BUTTON_BACK);
InputManager.SetGameJoypadMaps(MAP_STYLE_2,ACTION_MENU_PAUSEMENU, _360_JOY_BUTTON_START);
InputManager.SetGameJoypadMaps(MAP_STYLE_2,ACTION_MENU_STICK_PRESS, _360_JOY_BUTTON_LTHUMB);
InputManager.SetGameJoypadMaps(MAP_STYLE_2,ACTION_MENU_OTHER_STICK_PRESS, _360_JOY_BUTTON_RTHUMB);
InputManager.SetGameJoypadMaps(MAP_STYLE_2,ACTION_MENU_OTHER_STICK_UP, _360_JOY_BUTTON_RSTICK_UP);
InputManager.SetGameJoypadMaps(MAP_STYLE_2,ACTION_MENU_OTHER_STICK_DOWN, _360_JOY_BUTTON_RSTICK_DOWN);
InputManager.SetGameJoypadMaps(MAP_STYLE_2,ACTION_MENU_OTHER_STICK_LEFT, _360_JOY_BUTTON_RSTICK_LEFT);
InputManager.SetGameJoypadMaps(MAP_STYLE_2,ACTION_MENU_OTHER_STICK_RIGHT, _360_JOY_BUTTON_RSTICK_RIGHT);
InputManager.SetGameJoypadMaps(MAP_STYLE_2,MINECRAFT_ACTION_DPAD_LEFT, _360_JOY_BUTTON_DPAD_LEFT);
InputManager.SetGameJoypadMaps(MAP_STYLE_2,MINECRAFT_ACTION_DPAD_RIGHT, _360_JOY_BUTTON_DPAD_RIGHT);
InputManager.SetGameJoypadMaps(MAP_STYLE_2,MINECRAFT_ACTION_DPAD_UP, _360_JOY_BUTTON_DPAD_UP);
InputManager.SetGameJoypadMaps(MAP_STYLE_2,MINECRAFT_ACTION_DPAD_DOWN, _360_JOY_BUTTON_DPAD_DOWN);
}
#if 0
HRESULT InitD3D( IDirect3DDevice9 **ppDevice,
D3DPRESENT_PARAMETERS *pd3dPP )
{
IDirect3D9 *pD3D;
pD3D = Direct3DCreate9( D3D_SDK_VERSION );
// Set up the structure used to create the D3DDevice
// Using a permanent 1280x720 backbuffer now no matter what the actual video resolution.right Have also disabled letterboxing,
// which would letterbox a 1280x720 output if it detected a 4:3 video source - we're doing an anamorphic squash in this
// mode so don't need this functionality.
ZeroMemory( pd3dPP, sizeof(D3DPRESENT_PARAMETERS) );
XVIDEO_MODE VideoMode;
XGetVideoMode( &VideoMode );
g_bWidescreen = VideoMode.fIsWideScreen;
pd3dPP->BackBufferWidth = 1280;
pd3dPP->BackBufferHeight = 720;
pd3dPP->BackBufferFormat = D3DFMT_A8R8G8B8;
pd3dPP->BackBufferCount = 1;
pd3dPP->EnableAutoDepthStencil = TRUE;
pd3dPP->AutoDepthStencilFormat = D3DFMT_D24S8;
pd3dPP->SwapEffect = D3DSWAPEFFECT_DISCARD;
pd3dPP->PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
//pd3dPP->Flags = D3DPRESENTFLAG_NO_LETTERBOX;
//ERR[D3D]: Can't set D3DPRESENTFLAG_NO_LETTERBOX when wide-screen is enabled
// in the launcher/dashboard.
if(g_bWidescreen)
pd3dPP->Flags=0;
else
pd3dPP->Flags = D3DPRESENTFLAG_NO_LETTERBOX;
// Create the device.
return pD3D->CreateDevice(
0,
D3DDEVTYPE_HAL,
nullptr,
D3DCREATE_HARDWARE_VERTEXPROCESSING|D3DCREATE_BUFFER_2_FRAMES,
pd3dPP,
ppDevice );
}
#endif
//#define MEMORY_TRACKING
#ifdef MEMORY_TRACKING
void ResetMem();
void DumpMem();
void MemPixStuff();
#else
void MemSect(int sect)
{
}
#endif
HINSTANCE g_hInst = nullptr;
HWND g_hWnd = nullptr;
D3D_DRIVER_TYPE g_driverType = D3D_DRIVER_TYPE_NULL;
D3D_FEATURE_LEVEL g_featureLevel = D3D_FEATURE_LEVEL_11_0;
ID3D11Device* g_pd3dDevice = nullptr;
ID3D11DeviceContext* g_pImmediateContext = nullptr;
IDXGISwapChain* g_pSwapChain = nullptr;
bool g_bVSync = false;
// FLIP-MODE TEST: set by the DXGI_FEATURE_PRESENT_ALLOW_TEARING probe in InitDevice.
// Drives the ALLOW_TEARING swap chain flag and the DXGI_PRESENT_ALLOW_TEARING Present flag.
static bool g_bTearingSupported = false;
static bool g_bPendingExclusiveFullscreen = false;
static bool g_bPendingExclusiveFullscreenValue = false;
// Captures the D3D11 back buffer and saves it as a PNG screenshot.
// Returns true on success and sets outFilename to the saved filename.
static bool TakeScreenshot(wstring& outFilename)
{
if (!g_pSwapChain || !g_pd3dDevice || !g_pImmediateContext)
return false;
ID3D11Texture2D* pBackBuffer = nullptr;
HRESULT hr = g_pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&pBackBuffer);
if (FAILED(hr))
return false;
D3D11_TEXTURE2D_DESC desc;
pBackBuffer->GetDesc(&desc);
desc.Usage = D3D11_USAGE_STAGING;
desc.BindFlags = 0;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
desc.MiscFlags = 0;
bool success = false;
ID3D11Texture2D* pStaging = nullptr;
hr = g_pd3dDevice->CreateTexture2D(&desc, nullptr, &pStaging);
if (SUCCEEDED(hr))
{
g_pImmediateContext->CopyResource(pStaging, pBackBuffer);
wchar_t exePath[MAX_PATH];
GetModuleFileNameW(NULL, exePath, MAX_PATH);
wchar_t* lastSlash = wcsrchr(exePath, L'\\');
if (lastSlash) *(lastSlash + 1) = L'\0';
wstring screenshotDirPath = wstring(exePath) + L"screenshots";
CreateDirectoryW(screenshotDirPath.c_str(), NULL);
SYSTEMTIME st;
GetLocalTime(&st);
wchar_t filename[128];
swprintf_s(filename, L"%04d-%02d-%02d_%02d.%02d.%02d.png",
st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
wstring screenshotPath = screenshotDirPath + L"\\" + filename;
D3D11_MAPPED_SUBRESOURCE mapped;
hr = g_pImmediateContext->Map(pStaging, 0, D3D11_MAP_READ, 0, &mapped);
if (SUCCEEDED(hr))
{
unsigned char* rgba = new unsigned char[desc.Width * desc.Height * 4];
for (UINT row = 0; row < desc.Height; row++)
{
unsigned char* src = (unsigned char*)mapped.pData + row * mapped.RowPitch;
unsigned char* dst = rgba + row * desc.Width * 4;
memcpy(dst, src, desc.Width * 4);
for (UINT x = 0; x < desc.Width; x++)
dst[x * 4 + 3] = 0xFF;
}
g_pImmediateContext->Unmap(pStaging, 0);
string narrowPath(screenshotPath.begin(), screenshotPath.end());
int writeResult = stbi_write_png(narrowPath.c_str(), desc.Width, desc.Height, 4, rgba, desc.Width * 4);
delete[] rgba;
if (writeResult)
{
outFilename = filename;
success = true;
}
}
pStaging->Release();
}
pBackBuffer->Release();
return success;
}
ID3D11RenderTargetView* g_pRenderTargetView = nullptr;
ID3D11DepthStencilView* g_pDepthStencilView = nullptr;
ID3D11Texture2D* g_pDepthStencilBuffer = nullptr;
static const float kClearColorWhite[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
static const float kClearColorBlack[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
// FLIP-MODE TEST: toggle for the D3D11 debug layer.
// The debug layer has significant per-frame overhead (observed FPS drop),
// so default it off. Flip to true, rebuild, and re-run when you need to
// capture ResizeBuffers error details via the info queue.
static const bool kFlipTestEnableDebugLayer = true;
// FLIP-MODE TEST: dedicated file logger that works in release builds.
// Writes to flip_test.log next to the current working directory (normally the
// folder containing the exe). Unbuffered so we see output even if the game
// crashes mid-operation. Also echoes to OutputDebugString so DebugView / a
// debugger sees it too.
static FILE* g_pFlipTestLog = nullptr;
static void FlipTestLogEnsureOpen()
{
if (g_pFlipTestLog) return;
fopen_s(&g_pFlipTestLog, "flip_test.log", "w");
if (!g_pFlipTestLog) return;
setvbuf(g_pFlipTestLog, nullptr, _IONBF, 0); // unbuffered
SYSTEMTIME st;
GetLocalTime(&st);
fprintf(g_pFlipTestLog,
"=== FLIP TEST LOG (started %04d-%02d-%02d %02d:%02d:%02d) ===\n",
st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
}
static void FlipTestLog(const char* fmt, ...)
{
FlipTestLogEnsureOpen();
char buf[2048];
va_list args;
va_start(args, fmt);
_vsnprintf_s(buf, sizeof(buf), _TRUNCATE, fmt, args);
va_end(args);
if (g_pFlipTestLog) { fputs(buf, g_pFlipTestLog); fflush(g_pFlipTestLog); }
OutputDebugStringA(buf);
}
// FLIP-MODE TEST: drain and print every stored D3D11 debug layer message.
// Call this after operations we want to diagnose (CreateDevice, ResizeBuffers).
// Silently does nothing if the debug layer is unavailable (returns NULL for
// the InfoQueue interface), but still writes a log line so we know it was
// called.
static void DumpD3D11InfoQueue(const char* label)
{
if (!g_pd3dDevice) { FlipTestLog("[InfoQueue] %s: no device\n", label); return; }
ID3D11InfoQueue* pInfoQueue = nullptr;
HRESULT hr = g_pd3dDevice->QueryInterface(__uuidof(ID3D11InfoQueue), (void**)&pInfoQueue);
if (FAILED(hr) || !pInfoQueue)
{
FlipTestLog("[InfoQueue] %s: unavailable (debug layer not active)\n", label);
return;
}
UINT64 numMessages = pInfoQueue->GetNumStoredMessages();
FlipTestLog("[InfoQueue] %s: %llu queued message(s)\n",
label, (unsigned long long)numMessages);
for (UINT64 i = 0; i < numMessages; i++)
{
SIZE_T msgLen = 0;
hr = pInfoQueue->GetMessage(i, nullptr, &msgLen);
if (FAILED(hr) || msgLen == 0) continue;
D3D11_MESSAGE* pMsg = (D3D11_MESSAGE*)malloc(msgLen);
if (!pMsg) continue;
hr = pInfoQueue->GetMessage(i, pMsg, &msgLen);
if (SUCCEEDED(hr))
{
const char* sev = "?";
switch (pMsg->Severity)
{
case D3D11_MESSAGE_SEVERITY_CORRUPTION: sev = "CORRUPTION"; break;
case D3D11_MESSAGE_SEVERITY_ERROR: sev = "ERROR"; break;
case D3D11_MESSAGE_SEVERITY_WARNING: sev = "WARNING"; break;
case D3D11_MESSAGE_SEVERITY_INFO: sev = "INFO"; break;
case D3D11_MESSAGE_SEVERITY_MESSAGE: sev = "MESSAGE"; break;
}
FlipTestLog(" [%s] #%d: %.*s\n", sev, (int)pMsg->ID,
(int)pMsg->DescriptionByteLength, pMsg->pDescription);
}
free(pMsg);
}
pInfoQueue->ClearStoredMessages();
pInfoQueue->Release();
}
// FLIP-MODE TEST: configure the D3D11 debug layer's info queue.
static void SetupD3D11InfoQueue()
{
if (!g_pd3dDevice) return;
ID3D11InfoQueue* pInfoQueue = nullptr;
HRESULT hr = g_pd3dDevice->QueryInterface(__uuidof(ID3D11InfoQueue), (void**)&pInfoQueue);
if (FAILED(hr) || !pInfoQueue)
{
FlipTestLog("[InfoQueue] not available (debug layer not installed or not enabled)\n");
return;
}
D3D11_INFO_QUEUE_FILTER filter = {};
D3D11_MESSAGE_SEVERITY denied[] = { D3D11_MESSAGE_SEVERITY_INFO };
filter.DenyList.NumSeverities = ARRAYSIZE(denied);
filter.DenyList.pSeverityList = denied;
pInfoQueue->PushStorageFilter(&filter);
// Raise the storage limit well above the default (1024) so ReportLive
// output from busy games doesn't get truncated.
pInfoQueue->SetMessageCountLimit((UINT64)-1);
FlipTestLog("[InfoQueue] installed, CORRUPTION/ERROR/WARNING captured, limit=unlimited\n");
pInfoQueue->Release();
}
// FLIP-MODE TEST: the D3D11 InfoQueue only captures D3D11 messages.
// IDXGISwapChain::ResizeBuffers is a DXGI call, so its errors go to the
// SEPARATE DXGI info queue. We obtain it via DXGIGetDebugInterface from
// dxgidebug.dll (loaded dynamically to avoid an import table dependency).
//
// kDXGIDebugAll is a GUID declared in dxgidebug.h via DEFINE_GUID, which
// only produces an `extern` declaration unless `dxguid.lib` is linked OR
// `INITGUID` is defined before the include. Our link line doesn't have
// dxguid.lib, so we define the GUID locally as a static const to avoid
// adding a lib dependency or fighting with INITGUID ordering.
static const GUID kDXGIDebugAll =
{ 0xe48ae283, 0xda80, 0x490b, { 0x87, 0xe6, 0x43, 0xe9, 0xa9, 0xcf, 0xda, 0x08 } };
static IDXGIInfoQueue* g_pDXGIInfoQueue = nullptr;
// Forward declarations (ReportLiveObjects calls DumpDXGIInfoQueue which is defined below)
static void DumpDXGIInfoQueue(const char* label);
static void SetupDXGIInfoQueue()
{
HMODULE hDxgiDebug = LoadLibraryA("dxgidebug.dll");
if (!hDxgiDebug)
{
FlipTestLog("[DXGIInfoQueue] dxgidebug.dll not loaded (GetLastError=%lu)\n", GetLastError());
return;
}
typedef HRESULT (WINAPI *PFN_DXGI_GET_DEBUG_INTERFACE)(REFIID, void**);
PFN_DXGI_GET_DEBUG_INTERFACE pGet =
(PFN_DXGI_GET_DEBUG_INTERFACE)GetProcAddress(hDxgiDebug, "DXGIGetDebugInterface");
if (!pGet)
{
FlipTestLog("[DXGIInfoQueue] DXGIGetDebugInterface symbol not found\n");
return;
}
HRESULT hr = pGet(__uuidof(IDXGIInfoQueue), (void**)&g_pDXGIInfoQueue);
if (FAILED(hr) || !g_pDXGIInfoQueue)
{
FlipTestLog("[DXGIInfoQueue] DXGIGetDebugInterface failed hr=0x%08X\n", (unsigned)hr);
return;
}
// Filter out INFO noise, keep CORRUPTION/ERROR/WARNING.
DXGI_INFO_QUEUE_FILTER filter = {};
DXGI_INFO_QUEUE_MESSAGE_SEVERITY denied[] = { DXGI_INFO_QUEUE_MESSAGE_SEVERITY_INFO };
filter.DenyList.NumSeverities = ARRAYSIZE(denied);
filter.DenyList.pSeverityList = denied;
g_pDXGIInfoQueue->PushStorageFilter(kDXGIDebugAll, &filter);
g_pDXGIInfoQueue->SetMessageCountLimit(kDXGIDebugAll, (UINT64)-1);
FlipTestLog("[DXGIInfoQueue] installed, DXGI CORRUPTION/ERROR/WARNING captured, limit=unlimited\n");
}
// FLIP-MODE TEST: dump every live D3D11 and DXGI object via ReportLiveObjects.
// This is the definitive way to see what's holding refs to the swap chain
// buffers. The output goes to the info queues as MESSAGE-severity items, which
// our filter lets through.
static void ReportLiveObjects(const char* label)
{
FlipTestLog("[ReportLive] %s:\n", label);
// D3D11 side
if (g_pd3dDevice)
{
ID3D11Debug* pDebug = nullptr;
HRESULT hr = g_pd3dDevice->QueryInterface(__uuidof(ID3D11Debug), (void**)&pDebug);
if (SUCCEEDED(hr) && pDebug)
{
FlipTestLog(" calling ID3D11Debug::ReportLiveDeviceObjects(DETAIL)\n");
pDebug->ReportLiveDeviceObjects(D3D11_RLDO_DETAIL);
pDebug->Release();
}
else
{
FlipTestLog(" ID3D11Debug not available hr=0x%08X\n", (unsigned)hr);
}
}
// DXGI side (via dxgidebug.dll dynamic load)
HMODULE hDxgiDebug = LoadLibraryA("dxgidebug.dll");
if (hDxgiDebug)
{
typedef HRESULT (WINAPI *PFN_DXGI_GET_DEBUG_INTERFACE)(REFIID, void**);
PFN_DXGI_GET_DEBUG_INTERFACE pGet =
(PFN_DXGI_GET_DEBUG_INTERFACE)GetProcAddress(hDxgiDebug, "DXGIGetDebugInterface");
if (pGet)
{
IDXGIDebug* pDXGIDebug = nullptr;
HRESULT hr = pGet(__uuidof(IDXGIDebug), (void**)&pDXGIDebug);
if (SUCCEEDED(hr) && pDXGIDebug)
{
FlipTestLog(" calling IDXGIDebug::ReportLiveObjects(ALL, RLO_ALL)\n");
// DXGI_DEBUG_RLO_ALL = 0x7 (SUMMARY | DETAIL | IGNORE_INTERNAL)
pDXGIDebug->ReportLiveObjects(kDXGIDebugAll, DXGI_DEBUG_RLO_ALL);
pDXGIDebug->Release();
}
else
{
FlipTestLog(" IDXGIDebug not available hr=0x%08X\n", (unsigned)hr);
}
}
}
// Drain both info queues to capture the ReportLive output
DumpD3D11InfoQueue("ReportLive (D3D11)");
DumpDXGIInfoQueue("ReportLive (DXGI)");
}
static void DumpDXGIInfoQueue(const char* label)
{
if (!g_pDXGIInfoQueue) { FlipTestLog("[DXGIInfoQueue] %s: not installed\n", label); return; }
UINT64 numMessages = g_pDXGIInfoQueue->GetNumStoredMessages(kDXGIDebugAll);
FlipTestLog("[DXGIInfoQueue] %s: %llu queued message(s)\n",
label, (unsigned long long)numMessages);
for (UINT64 i = 0; i < numMessages; i++)
{
SIZE_T msgLen = 0;
HRESULT hr = g_pDXGIInfoQueue->GetMessage(kDXGIDebugAll, i, nullptr, &msgLen);
if (FAILED(hr) || msgLen == 0) continue;
DXGI_INFO_QUEUE_MESSAGE* pMsg = (DXGI_INFO_QUEUE_MESSAGE*)malloc(msgLen);
if (!pMsg) continue;
hr = g_pDXGIInfoQueue->GetMessage(kDXGIDebugAll, i, pMsg, &msgLen);
if (SUCCEEDED(hr))
{
const char* sev = "?";
switch (pMsg->Severity)
{
case DXGI_INFO_QUEUE_MESSAGE_SEVERITY_CORRUPTION: sev = "CORRUPTION"; break;
case DXGI_INFO_QUEUE_MESSAGE_SEVERITY_ERROR: sev = "ERROR"; break;
case DXGI_INFO_QUEUE_MESSAGE_SEVERITY_WARNING: sev = "WARNING"; break;
case DXGI_INFO_QUEUE_MESSAGE_SEVERITY_INFO: sev = "INFO"; break;
case DXGI_INFO_QUEUE_MESSAGE_SEVERITY_MESSAGE: sev = "MESSAGE"; break;
}
FlipTestLog(" DXGI [%s] #%d: %.*s\n", sev, (int)pMsg->ID,
(int)pMsg->DescriptionByteLength, pMsg->pDescription);
}
free(pMsg);
}
g_pDXGIInfoQueue->ClearStoredMessages(kDXGIDebugAll);
}
//
// FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// PURPOSE: Processes messages for the main window.
//
// WM_COMMAND - process the application menu
// WM_PAINT - Paint the main window
// WM_DESTROY - post a quit message and return
// WM_SIZE - handle resizing logic to support Any Aspect Ratio
//
//
static bool ResizeD3D(int newW, int newH); // forward declaration
static bool g_bInSizeMove = false; // true while the user is dragging the window border
static int g_pendingResizeW = 0; // deferred resize dimensions
static int g_pendingResizeH = 0;
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
switch (message)
{
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProcW(hWnd, message, wParam, lParam);
}
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code here...
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_KILLFOCUS:
g_KBMInput.ClearAllState();
g_KBMInput.SetWindowFocused(false);
if (g_KBMInput.IsMouseGrabbed())
g_KBMInput.SetMouseGrabbed(false);
break;
case WM_SETFOCUS:
g_KBMInput.SetWindowFocused(true);
break;
case WM_CHAR:
// Buffer typed characters so UIScene_Keyboard can dispatch them to the Iggy Flash player
if (wParam >= 0x20 || wParam == 0x08 || wParam == 0x0D) // printable chars + backspace + enter
g_KBMInput.OnChar(static_cast<wchar_t>(wParam));
break;
case WM_KEYDOWN:
case WM_SYSKEYDOWN:
{
int vk = static_cast<int>(wParam);
if ((lParam & 0x40000000) && vk != VK_LEFT && vk != VK_RIGHT && vk != VK_BACK)
break;
#ifdef _WINDOWS64
const Minecraft* pm = Minecraft::GetInstance();
ChatScreen* chat = pm && pm->screen ? dynamic_cast<ChatScreen*>(pm->screen) : nullptr;
if (chat)
{
if (vk == 'V' && (GetKeyState(VK_CONTROL) & 0x8000))
{ chat->handlePasteRequest(); break; }
if ((vk == VK_UP || vk == VK_DOWN) && !(lParam & 0x40000000))
{ if (vk == VK_UP) chat->handleHistoryUp(); else chat->handleHistoryDown(); break; }
if (vk >= '1' && vk <= '9') // Prevent hotkey conflicts
break;
if (vk == VK_SHIFT)
break;
}
#endif
if (vk == VK_SHIFT)
vk = (MapVirtualKey((lParam >> 16) & 0xFF, MAPVK_VSC_TO_VK_EX) == VK_RSHIFT) ? VK_RSHIFT : VK_LSHIFT;
else if (vk == VK_CONTROL)
vk = (lParam & (1 << 24)) ? VK_RCONTROL : VK_LCONTROL;
else if (vk == VK_MENU)
vk = (lParam & (1 << 24)) ? VK_RMENU : VK_LMENU;
g_KBMInput.OnKeyDown(vk);
return DefWindowProcW(hWnd, message, wParam, lParam);
}
case WM_KEYUP:
case WM_SYSKEYUP:
{
int vk = static_cast<int>(wParam);
if (vk == VK_SHIFT)
vk = (MapVirtualKey((lParam >> 16) & 0xFF, MAPVK_VSC_TO_VK_EX) == VK_RSHIFT) ? VK_RSHIFT : VK_LSHIFT;
else if (vk == VK_CONTROL)
vk = (lParam & (1 << 24)) ? VK_RCONTROL : VK_LCONTROL;
else if (vk == VK_MENU)
vk = (lParam & (1 << 24)) ? VK_RMENU : VK_LMENU;
g_KBMInput.OnKeyUp(vk);
break;
}
case WM_LBUTTONDOWN:
g_KBMInput.OnMouseButtonDown(KeyboardMouseInput::MOUSE_LEFT);
break;
case WM_LBUTTONUP:
g_KBMInput.OnMouseButtonUp(KeyboardMouseInput::MOUSE_LEFT);
break;
case WM_RBUTTONDOWN:
g_KBMInput.OnMouseButtonDown(KeyboardMouseInput::MOUSE_RIGHT);
break;
case WM_RBUTTONUP:
g_KBMInput.OnMouseButtonUp(KeyboardMouseInput::MOUSE_RIGHT);
break;
case WM_MBUTTONDOWN:
g_KBMInput.OnMouseButtonDown(KeyboardMouseInput::MOUSE_MIDDLE);
break;
case WM_MBUTTONUP:
g_KBMInput.OnMouseButtonUp(KeyboardMouseInput::MOUSE_MIDDLE);
break;
case WM_MOUSEMOVE:
g_KBMInput.OnMouseMove(LOWORD(lParam), HIWORD(lParam));
break;
case WM_MOUSEWHEEL:
g_KBMInput.OnMouseWheel(GET_WHEEL_DELTA_WPARAM(wParam));
break;
case WM_INPUT:
{
UINT dwSize = 0;
GetRawInputData((HRAWINPUT)lParam, RID_INPUT, nullptr, &dwSize, sizeof(RAWINPUTHEADER));
if (dwSize > 0 && dwSize <= 256)
{
BYTE rawBuffer[256];
if (GetRawInputData((HRAWINPUT)lParam, RID_INPUT, rawBuffer, &dwSize, sizeof(RAWINPUTHEADER)) == dwSize)
{
const RAWINPUT* raw = (RAWINPUT*)rawBuffer;
if (raw->header.dwType == RIM_TYPEMOUSE)
{
g_KBMInput.OnRawMouseDelta(raw->data.mouse.lLastX, raw->data.mouse.lLastY);
}
}
}
}
break;
case WM_ENTERSIZEMOVE:
g_bInSizeMove = true;
break;
case WM_EXITSIZEMOVE:
g_bInSizeMove = false;
if (g_pendingResizeW > 0 && g_pendingResizeH > 0)
{
// g_rScreenWidth/Height updated inside ResizeD3D to backbuffer dims
ResizeD3D(g_pendingResizeW, g_pendingResizeH);
g_pendingResizeW = 0;
g_pendingResizeH = 0;
}
break;
case WM_SIZE:
{
int newW = LOWORD(lParam);
int newH = HIWORD(lParam);
if (newW > 0 && newH > 0)
{
if (g_bInSizeMove)
{
// Just store the latest size, resize when dragging ends
g_pendingResizeW = newW;
g_pendingResizeH = newH;
}
else
{
// Immediate resize (maximize, programmatic resize, etc.)
// g_rScreenWidth/Height updated inside ResizeD3D to backbuffer dims
ResizeD3D(newW, newH);
}
}
}
break;
default:
return DefWindowProcW(hWnd, message, wParam, lParam);
}
return 0;
}
//
// FUNCTION: MyRegisterClass()
//
// PURPOSE: Registers the window class.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEXW wcex;
wcex.cbSize = sizeof(WNDCLASSEXW);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIconW(hInstance, L"Minecraft");
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = L"Minecraft";
wcex.lpszClassName = L"MinecraftClass";
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_MINECRAFTWINDOWS));
return RegisterClassExW(&wcex);
}
//
// FUNCTION: InitInstance(HINSTANCE, int)
//
// PURPOSE: Saves instance handle and creates main window
//
// COMMENTS:
//
// In this function, we save the instance handle in a global variable and
// create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
g_hInst = hInstance; // Store instance handle in our global variable
RECT wr = {0, 0, g_rScreenWidth, g_rScreenHeight}; // set the size, but not the position
AdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW, FALSE); // adjust the size
g_hWnd = CreateWindowW( L"MinecraftClass",
L"Minecraft",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
0,
wr.right - wr.left, // width of the window
wr.bottom - wr.top, // height of the window
nullptr,
nullptr,
hInstance,
nullptr);
if (!g_hWnd)
{
return FALSE;
}
ShowWindow(g_hWnd, (nCmdShow != SW_HIDE) ? SW_SHOWMAXIMIZED : nCmdShow);
UpdateWindow(g_hWnd);
return TRUE;
}
// 4J Stu - These functions are referenced from the Windows Input library
void ClearGlobalText()
{
// clear the global text
memset(chGlobalText,0,256);
memset(ui16GlobalText,0,512);
}
uint16_t *GetGlobalText()
{
//copy the ch text to ui16
char * pchBuffer=(char *)ui16GlobalText;
for(int i=0;i<256;i++)
{
pchBuffer[i*2]=chGlobalText[i];
}
return ui16GlobalText;
}
void SeedEditBox()
{
DialogBox(hMyInst, MAKEINTRESOURCE(IDD_SEED),
g_hWnd, reinterpret_cast<DLGPROC>(DlgProc));
}
//---------------------------------------------------------------------------
LRESULT CALLBACK DlgProc(HWND hWndDlg, UINT Msg, WPARAM wParam, LPARAM lParam)
{
switch(Msg)
{
case WM_INITDIALOG:
return TRUE;
case WM_COMMAND:
switch(wParam)
{
case IDOK:
// Set the text
GetDlgItemText(hWndDlg,IDC_EDIT,chGlobalText,256);
EndDialog(hWndDlg, 0);
return TRUE;
}
break;
}
return FALSE;
}
//--------------------------------------------------------------------------------------
// Create Direct3D device and swap chain
//--------------------------------------------------------------------------------------
HRESULT InitDevice()
{
HRESULT hr = S_OK;
RECT rc;
GetClientRect( g_hWnd, &rc );
UINT width = rc.right - rc.left;
UINT height = rc.bottom - rc.top;
//app.DebugPrintf("width: %d, height: %d\n", width, height);
width = g_rScreenWidth;
height = g_rScreenHeight;
//app.DebugPrintf("width: %d, height: %d\n", width, height);
FlipTestLog("[InitDevice] entering, requested %dx%d\n", width, height);
UINT createDeviceFlags = 0;
#ifdef _DEBUG
createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG;
#endif
// FLIP-MODE TEST: debug layer costs a lot of FPS, so only enable it when
// the test toggle is set AND we actually want to capture info queue data.
if (kFlipTestEnableDebugLayer)
createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG;
D3D_DRIVER_TYPE driverTypes[] =
{
D3D_DRIVER_TYPE_HARDWARE,
D3D_DRIVER_TYPE_WARP,
D3D_DRIVER_TYPE_REFERENCE,
};
UINT numDriverTypes = ARRAYSIZE( driverTypes );
D3D_FEATURE_LEVEL featureLevels[] =
{
D3D_FEATURE_LEVEL_11_0,
D3D_FEATURE_LEVEL_10_1,
D3D_FEATURE_LEVEL_10_0,
};
UINT numFeatureLevels = ARRAYSIZE( featureLevels );
// FLIP-MODE TEST: probe for tearing support before creating the swap chain.
// Needs IDXGIFactory5 (Windows 10 Anniversary Update+).
{
IDXGIFactory5* factory5 = nullptr;
if (SUCCEEDED(CreateDXGIFactory1(__uuidof(IDXGIFactory5), (void**)&factory5)))
{
BOOL allowTearing = FALSE;
if (SUCCEEDED(factory5->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allowTearing, sizeof(allowTearing))))
g_bTearingSupported = (allowTearing == TRUE);
factory5->Release();
}
FlipTestLog("[InitDevice] tearing support = %s\n", g_bTearingSupported ? "yes" : "no");
}
// FLIP-MODE TEST: FLIP_DISCARD swap chain for low-latency presentation
// with tearing support. BufferCount must be >= 2 for flip mode.
// SHADER_INPUT is valid for flip mode (per DXGI docs) so we keep it.
DXGI_SWAP_CHAIN_DESC sd;
ZeroMemory( &sd, sizeof( sd ) );
sd.BufferCount = 2;
sd.BufferDesc.Width = width;
sd.BufferDesc.Height = height;
sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
sd.BufferDesc.RefreshRate.Numerator = 0;
sd.BufferDesc.RefreshRate.Denominator = 0;
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_SHADER_INPUT;
sd.OutputWindow = g_hWnd;
sd.SampleDesc.Count = 1;
sd.SampleDesc.Quality = 0;
sd.Windowed = TRUE;
sd.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
sd.Flags = g_bTearingSupported ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0;
FlipTestLog("[InitDevice] calling D3D11CreateDeviceAndSwapChain (flags=0x%X, flip=yes, bc=2, tearing=%s)\n",
createDeviceFlags, g_bTearingSupported ? "yes" : "no");
for( UINT driverTypeIndex = 0; driverTypeIndex < numDriverTypes; driverTypeIndex++ )
{
g_driverType = driverTypes[driverTypeIndex];
hr = D3D11CreateDeviceAndSwapChain( nullptr, g_driverType, nullptr, createDeviceFlags, featureLevels, numFeatureLevels,
D3D11_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice, &g_featureLevel, &g_pImmediateContext );
FlipTestLog("[InitDevice] driver %u result hr=0x%08X\n", driverTypeIndex, (unsigned)hr);
if( HRESULT_SUCCEEDED( hr ) )
break;
}
// FLIP-MODE TEST: if the debug layer isn't installed, retry without the flag
// so the game still boots. We lose info queue capture but at least we see
// if flip mode itself works.
if (FAILED(hr) && (createDeviceFlags & D3D11_CREATE_DEVICE_DEBUG))
{
FlipTestLog("[InitDevice] retrying without debug flag\n");
createDeviceFlags &= ~D3D11_CREATE_DEVICE_DEBUG;
for( UINT driverTypeIndex = 0; driverTypeIndex < numDriverTypes; driverTypeIndex++ )
{
g_driverType = driverTypes[driverTypeIndex];
hr = D3D11CreateDeviceAndSwapChain( nullptr, g_driverType, nullptr, createDeviceFlags, featureLevels, numFeatureLevels,
D3D11_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice, &g_featureLevel, &g_pImmediateContext );
if( HRESULT_SUCCEEDED( hr ) )
break;
}
}
if( FAILED( hr ) )
{
FlipTestLog("[InitDevice] FAILED final hr=0x%08X\n", (unsigned)hr);
return hr;
}
FlipTestLog("[InitDevice] D3D11CreateDeviceAndSwapChain OK, device=%p swapchain=%p context=%p\n",
g_pd3dDevice, g_pSwapChain, g_pImmediateContext);
// FLIP-MODE TEST: install BOTH the D3D11 info queue (for D3D11 errors) and
// the DXGI info queue (for DXGI/swap-chain errors — which is what ResizeBuffers
// emits). These are separate layers and need separate setup.
SetupD3D11InfoQueue();
SetupDXGIInfoQueue();
DumpD3D11InfoQueue("after CreateDevice");
DumpDXGIInfoQueue("after CreateDevice");
// Create a render target view
ID3D11Texture2D* pBackBuffer = nullptr;
hr = g_pSwapChain->GetBuffer( 0, __uuidof( ID3D11Texture2D ), ( LPVOID* )&pBackBuffer );
if( FAILED( hr ) )
return hr;
FlipTestLog("[InitDevice] initial backbuffer (GetBuffer 0 at init) = %p\n", (void*)pBackBuffer);
// Create a depth stencil buffer
D3D11_TEXTURE2D_DESC descDepth;
ZeroMemory(&descDepth, sizeof(descDepth));
descDepth.Width = width;
descDepth.Height = height;
descDepth.MipLevels = 1;
descDepth.ArraySize = 1;
descDepth.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
descDepth.SampleDesc.Count = 1;
descDepth.SampleDesc.Quality = 0;
descDepth.Usage = D3D11_USAGE_DEFAULT;
descDepth.BindFlags = D3D11_BIND_DEPTH_STENCIL;
descDepth.CPUAccessFlags = 0;
descDepth.MiscFlags = 0;
hr = g_pd3dDevice->CreateTexture2D(&descDepth, nullptr, &g_pDepthStencilBuffer);
D3D11_DEPTH_STENCIL_VIEW_DESC descDSView;
ZeroMemory(&descDSView, sizeof(descDSView));
descDSView.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
descDSView.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
descDSView.Texture2D.MipSlice = 0;
hr = g_pd3dDevice->CreateDepthStencilView(g_pDepthStencilBuffer, &descDSView, &g_pDepthStencilView);
hr = g_pd3dDevice->CreateRenderTargetView( pBackBuffer, nullptr, &g_pRenderTargetView );
pBackBuffer->Release();
if( FAILED( hr ) )
return hr;
g_pImmediateContext->OMSetRenderTargets( 1, &g_pRenderTargetView, g_pDepthStencilView );
// Setup the viewport
D3D11_VIEWPORT vp;
vp.Width = static_cast<FLOAT>(width);
vp.Height = static_cast<FLOAT>(height);
vp.MinDepth = 0.0f;
vp.MaxDepth = 1.0f;
vp.TopLeftX = 0;
vp.TopLeftY = 0;
g_pImmediateContext->RSSetViewports( 1, &vp );
RenderManager.Initialise(g_pd3dDevice, g_pSwapChain);
PostProcesser::GetInstance().Init();
return S_OK;
}
//--------------------------------------------------------------------------------------
// Render the frame
//--------------------------------------------------------------------------------------
void Render()
{
// Just clear the backbuffer
const float ClearColor[4] = { 0.0f, 0.125f, 0.3f, 1.0f }; //red,green,blue,alpha
g_pImmediateContext->ClearRenderTargetView( g_pRenderTargetView, ClearColor );
g_pSwapChain->Present(0, 0);
}
//--------------------------------------------------------------------------------------
// Rebuild D3D11 resources after a window resize
//--------------------------------------------------------------------------------------
static bool ResizeD3D(int newW, int newH)
{
FlipTestLog("[ResizeD3D] called with %dx%d\n", newW, newH);
if (newW <= 0 || newH <= 0) { FlipTestLog("[ResizeD3D] bad size, skip\n"); return false; }
if (!g_pSwapChain) { FlipTestLog("[ResizeD3D] no swap chain, skip\n"); return false; }
if (!g_bResizeReady) { FlipTestLog("[ResizeD3D] not ready, skip\n"); return false; }
int bbW = newW;
int bbH = newH;
// InternalRenderManager member offsets (from decompiled Renderer.h):
// 0x10 m_pDevice (ID3D11Device*)
// 0x18 m_pDeviceContext (ID3D11DeviceContext*)
// 0x20 m_pSwapChain (IDXGISwapChain*)
// 0x28 renderTargetView (ID3D11RenderTargetView*) — backbuffer RTV
// 0x50 renderTargetShaderResourceView (ID3D11ShaderResourceView*)
// 0x98 depthStencilView (ID3D11DepthStencilView*)
// 0x5138 backBufferWidth (DWORD) — used by StartFrame() for viewport
// 0x513C backBufferHeight (DWORD) — used by StartFrame() for viewport
//
// Strategy: destroy old swap chain, create new one, patch Renderer's internal
// pointers directly. This avoids both ResizeBuffers (outstanding ref issues)
// and Initialise() (which wipes the texture table via memset).
// The Renderer's old RTV/SRV/DSV are intentionally NOT released — they become
// orphaned with the old swap chain. Tiny leak, but avoids fighting unknown refs.
char* pRM = (char*)&InternalRenderManager;
ID3D11RenderTargetView** ppRM_RTV = (ID3D11RenderTargetView**)(pRM + 0x28);
ID3D11ShaderResourceView** ppRM_SRV = (ID3D11ShaderResourceView**)(pRM + 0x50);
ID3D11DepthStencilView** ppRM_DSV = (ID3D11DepthStencilView**)(pRM + 0x98);
IDXGISwapChain** ppRM_SC = (IDXGISwapChain**)(pRM + 0x20);
DWORD* pRM_BBWidth = (DWORD*)(pRM + 0x5138);
DWORD* pRM_BBHeight = (DWORD*)(pRM + 0x513C);
// Verify offsets by checking device and swap chain pointers
ID3D11Device** ppRM_Device = (ID3D11Device**)(pRM + 0x10);
if (*ppRM_Device != g_pd3dDevice || *ppRM_SC != g_pSwapChain)
{
app.DebugPrintf("[RESIZE] ERROR: RenderManager offset verification failed! "
"device=%p (expected %p) swapchain=%p (expected %p)\n",
*ppRM_Device, g_pd3dDevice, *ppRM_SC, g_pSwapChain);
return false;
}
// Cross-check backbuffer dimension offsets against swap chain desc
DXGI_SWAP_CHAIN_DESC oldScDesc;
g_pSwapChain->GetDesc(&oldScDesc);
bool bbDimsValid = (*pRM_BBWidth == oldScDesc.BufferDesc.Width &&
*pRM_BBHeight == oldScDesc.BufferDesc.Height);
if (!bbDimsValid)
{
app.DebugPrintf("[RESIZE] WARNING: backBuffer dim offsets wrong: "
"stored=%ux%u, swapchain=%ux%u\n",
*pRM_BBWidth, *pRM_BBHeight, oldScDesc.BufferDesc.Width, oldScDesc.BufferDesc.Height);
}
// FLIP-MODE TEST: granular refcount probing to find who holds the hidden
// backbuffer ref. Probe returns the backbuffer refcount AFTER dropping the
// ref we added via GetBuffer. In flip mode, the expected steady-state count
// is typically 1 (DXGI) or 2 (DXGI + DWM composition).
auto probeBBRefcount = [](const char* stage) {
if (!g_pSwapChain) { FlipTestLog("[ResizeD3D] refcount %s = (no swap chain)\n", stage); return; }
ID3D11Texture2D* pBB = nullptr;
HRESULT hr = g_pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&pBB);
if (FAILED(hr) || !pBB) { FlipTestLog("[ResizeD3D] refcount %s = (GetBuffer failed hr=0x%08X)\n", stage, (unsigned)hr); return; }
ULONG rc = pBB->Release();
FlipTestLog("[ResizeD3D] refcount %s = %lu (backbuffer ptr=%p)\n", stage, rc, (void*)pBB);
};
probeBBRefcount("at ResizeD3D entry");
FlipTestLog("[ResizeD3D] g_pRenderTargetView=%p g_pDepthStencilView=%p g_pDepthStencilBuffer=%p\n",
(void*)g_pRenderTargetView, (void*)g_pDepthStencilView, (void*)g_pDepthStencilBuffer);
FlipTestLog("[ResizeD3D] Renderer slots on entry: RTV=%p SRV=%p DSV=%p\n",
(void*)*ppRM_RTV, (void*)*ppRM_SRV, (void*)*ppRM_DSV);
RenderManager.Suspend();
while (!RenderManager.Suspended()) { Sleep(1); }
probeBBRefcount("after RenderManager.Suspend");
PostProcesser::GetInstance().Cleanup();
probeBBRefcount("after PostProcesser::Cleanup");
// Explicitly unbind all render targets BEFORE ClearState. ClearState should
// also do this, but being explicit costs nothing and protects against
// driver quirks.
{
ID3D11RenderTargetView* nullRTV[8] = {};
g_pImmediateContext->OMSetRenderTargets(8, nullRTV, NULL);
}
probeBBRefcount("after OMSetRenderTargets(null)");
g_pImmediateContext->ClearState();
probeBBRefcount("after ClearState");
g_pImmediateContext->Flush();
probeBBRefcount("after Flush");
// FLIP-MODE TEST: wait for GPU to finish all pending work before touching
// the swap chain. Flush() submits commands but doesn't wait. An event
// query gives us a proper GPU-side fence.
{
D3D11_QUERY_DESC qd = {};
qd.Query = D3D11_QUERY_EVENT;
ID3D11Query* pQuery = nullptr;
if (SUCCEEDED(g_pd3dDevice->CreateQuery(&qd, &pQuery)) && pQuery)
{
g_pImmediateContext->End(pQuery);
BOOL done = FALSE;
int spins = 0;
while (spins++ < 1000)
{
HRESULT hrQ = g_pImmediateContext->GetData(pQuery, &done, sizeof(done), 0);
if (hrQ == S_OK && done) break;
Sleep(1);
}
FlipTestLog("[ResizeD3D] GPU idle wait: %d spins, done=%d\n", spins, (int)done);
pQuery->Release();
}
}
probeBBRefcount("after GPU idle wait");
// Probe refcounts on the RTV objects themselves. AddRef/Release trick:
// Release returns the new refcount after dropping our AddRef, which tells
// us how many other refs existed.
if (g_pRenderTargetView) {
g_pRenderTargetView->AddRef();
ULONG rtvRc = g_pRenderTargetView->Release();
FlipTestLog("[ResizeD3D] g_pRenderTargetView refcount (self) = %lu\n", rtvRc);
}
if (*ppRM_RTV) {
(*ppRM_RTV)->AddRef();
ULONG rmRtvRc = (*ppRM_RTV)->Release();
FlipTestLog("[ResizeD3D] *ppRM_RTV refcount (self) = %lu\n", rmRtvRc);
}
FlipTestLog("[ResizeD3D] about to Release(g_pRenderTargetView=%p)\n", (void*)g_pRenderTargetView);
if (g_pRenderTargetView) { g_pRenderTargetView->Release(); g_pRenderTargetView = NULL; }
probeBBRefcount("after Release(g_pRenderTargetView)");
if (g_pDepthStencilView) { g_pDepthStencilView->Release(); g_pDepthStencilView = NULL; }
if (g_pDepthStencilBuffer) { g_pDepthStencilBuffer->Release(); g_pDepthStencilBuffer = NULL; }
probeBBRefcount("after Release(g_pDepth*)");
// Release the Renderer's internal RTV (at offset 0x28). This is a
// DIFFERENT RTV object from g_pRenderTargetView, created by something
// during Renderer::Initialise, that also wraps the backbuffer. If
// ResizeBuffers fails, the fallback recovery path will recreate it from
// the current swap chain so in-world rendering keeps working.
if (*ppRM_RTV) {
FlipTestLog("[ResizeD3D] releasing *ppRM_RTV=%p\n", (void*)*ppRM_RTV);
(*ppRM_RTV)->Release();
*ppRM_RTV = nullptr;
probeBBRefcount("after Release(*ppRM_RTV)");
}
gdraw_D3D11_PreReset();
probeBBRefcount("after gdraw_D3D11_PreReset");
// FLIP-MODE TEST: use ResizeBuffers instead of destroy-and-create.
IDXGISwapChain* pOldSwapChain = g_pSwapChain; // kept for recovery-path symmetry
bool success = false;
HRESULT hr;
FlipTestLog("[ResizeD3D] pre-resize cleanup done, about to probe backbuffer\n");
// Probe the backbuffer refcount just before ResizeBuffers. If it's > 1,
// something else is holding a hidden ref and ResizeBuffers will fail.
{
ID3D11Texture2D* pBB = nullptr;
HRESULT hrProbe = g_pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&pBB);
if (SUCCEEDED(hrProbe) && pBB != nullptr)
{
ULONG rc = pBB->Release(); // Release returns the new refcount
FlipTestLog("[ResizeD3D] backbuffer refcount just before ResizeBuffers = %lu (want 1)\n", rc);
}
else
{
FlipTestLog("[ResizeD3D] GetBuffer probe failed hr=0x%08X\n", (unsigned)hrProbe);
}
}
// Call ResizeBuffers. Pass 0 for BufferCount and DXGI_FORMAT_UNKNOWN so DXGI
// preserves whatever the swap chain was originally created with. Flags MUST
// match the creation flags (ALLOW_TEARING must be set if it was set at create).
{
UINT resizeFlags = g_bTearingSupported ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0;
// FLIP-MODE TEST: right before ResizeBuffers, ask both debug layers to
// enumerate every live object. DXGI's error #19 says buffer references
// are outstanding but doesn't name them; ReportLiveObjects will.
ReportLiveObjects("pre-ResizeBuffers");
FlipTestLog("[ResizeD3D] calling ResizeBuffers(0, %d, %d, DXGI_FORMAT_UNKNOWN, 0x%X)\n",
bbW, bbH, resizeFlags);
// Drain any stale DXGI messages from before the call so the post-call dump is clean
DumpDXGIInfoQueue("pre-ResizeBuffers (drain)");
hr = g_pSwapChain->ResizeBuffers(0, (UINT)bbW, (UINT)bbH, DXGI_FORMAT_UNKNOWN, resizeFlags);
FlipTestLog("[ResizeD3D] ResizeBuffers returned hr=0x%08X\n", (unsigned)hr);
if (FAILED(hr))
{
DumpD3D11InfoQueue("after ResizeBuffers fail");
DumpDXGIInfoQueue("after ResizeBuffers fail");
goto postReset;
}
DumpD3D11InfoQueue("after ResizeBuffers success");
DumpDXGIInfoQueue("after ResizeBuffers success");
}
// Swap chain pointer is unchanged after ResizeBuffers. The Renderer's
// internal m_pSwapChain field (offset 0x20) still points to the correct
// object, so no patch needed.
// Create render target views from new backbuffer
{
ID3D11Texture2D* pBackBuffer = NULL;
hr = g_pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer);
if (FAILED(hr)) goto postReset;
// Our RTV
hr = g_pd3dDevice->CreateRenderTargetView(pBackBuffer, NULL, &g_pRenderTargetView);
if (FAILED(hr)) { pBackBuffer->Release(); goto postReset; }
// Renderer's internal RTV (offset 0x28)
hr = g_pd3dDevice->CreateRenderTargetView(pBackBuffer, NULL, ppRM_RTV);
if (FAILED(hr)) { pBackBuffer->Release(); goto postReset; }
// Renderer's SRV: separate texture matching backbuffer dims (used by CaptureThumbnail)
D3D11_TEXTURE2D_DESC backDesc = {};
pBackBuffer->GetDesc(&backDesc);
pBackBuffer->Release();
D3D11_TEXTURE2D_DESC srvDesc = backDesc;
srvDesc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
ID3D11Texture2D* srvTexture = NULL;
hr = g_pd3dDevice->CreateTexture2D(&srvDesc, NULL, &srvTexture);
if (SUCCEEDED(hr))
{
hr = g_pd3dDevice->CreateShaderResourceView(srvTexture, NULL, ppRM_SRV);
srvTexture->Release();
}
if (FAILED(hr)) goto postReset;
}
// Recreate depth stencil at backbuffer size
{
D3D11_TEXTURE2D_DESC descDepth = {};
descDepth.Width = bbW;
descDepth.Height = bbH;
descDepth.MipLevels = 1;
descDepth.ArraySize = 1;
descDepth.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
descDepth.SampleDesc.Count = 1;
descDepth.SampleDesc.Quality = 0;
descDepth.Usage = D3D11_USAGE_DEFAULT;
descDepth.BindFlags = D3D11_BIND_DEPTH_STENCIL;
hr = g_pd3dDevice->CreateTexture2D(&descDepth, NULL, &g_pDepthStencilBuffer);
if (FAILED(hr)) goto postReset;
D3D11_DEPTH_STENCIL_VIEW_DESC descDSView = {};
descDSView.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
descDSView.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
hr = g_pd3dDevice->CreateDepthStencilView(g_pDepthStencilBuffer, &descDSView, &g_pDepthStencilView);
if (FAILED(hr)) goto postReset;
}
// Patch Renderer's DSV (AddRef because both we and the Renderer reference it)
g_pDepthStencilView->AddRef();
*ppRM_DSV = g_pDepthStencilView;
// Update Renderer's cached backbuffer dimensions (StartFrame uses these for viewport)
if (bbDimsValid)
{
*pRM_BBWidth = (DWORD)bbW;
*pRM_BBHeight = (DWORD)bbH;
}
// Rebind render targets and viewport
g_pImmediateContext->OMSetRenderTargets(1, &g_pRenderTargetView, g_pDepthStencilView);
{
D3D11_VIEWPORT vp = {};
vp.Width = (FLOAT)bbW;
vp.Height = (FLOAT)bbH;
vp.MinDepth = 0.0f;
vp.MaxDepth = 1.0f;
g_pImmediateContext->RSSetViewports(1, &vp);
}
ui.updateRenderTargets(g_pRenderTargetView, g_pDepthStencilView);
ui.updateScreenSize(bbW, bbH);
// Track actual backbuffer dimensions for the rest of the engine
g_rScreenWidth = bbW;
g_rScreenHeight = bbH;
success = true;
postReset:
if (!success && g_pSwapChain != NULL)
{
// Failure recovery: recreate our views from whatever swap chain survived
// so ui.m_pRenderTargetView / m_pDepthStencilView don't dangle.
DXGI_SWAP_CHAIN_DESC recoveryDesc;
g_pSwapChain->GetDesc(&recoveryDesc);
int recW = (int)recoveryDesc.BufferDesc.Width;
int recH = (int)recoveryDesc.BufferDesc.Height;
if (g_pRenderTargetView == NULL)
{
ID3D11Texture2D* pBB = NULL;
if (SUCCEEDED(g_pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBB)))
{
g_pd3dDevice->CreateRenderTargetView(pBB, NULL, &g_pRenderTargetView);
pBB->Release();
}
}
// FLIP-MODE TEST: restore *ppRM_RTV if we nullified it, so in-world
// rendering keeps working after a failed ResizeBuffers. Create a new
// RTV against the current (unchanged) backbuffer.
if (*ppRM_RTV == NULL)
{
ID3D11Texture2D* pBB2 = NULL;
if (SUCCEEDED(g_pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBB2)))
{
HRESULT hrRe = g_pd3dDevice->CreateRenderTargetView(pBB2, NULL, ppRM_RTV);
FlipTestLog("[ResizeD3D] recovery: recreated *ppRM_RTV hr=0x%08X new=%p\n",
(unsigned)hrRe, (void*)*ppRM_RTV);
pBB2->Release();
}
}
if (g_pDepthStencilView == NULL)
{
D3D11_TEXTURE2D_DESC dd = {};
dd.Width = recW; dd.Height = recH; dd.MipLevels = 1; dd.ArraySize = 1;
dd.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
dd.SampleDesc.Count = 1; dd.Usage = D3D11_USAGE_DEFAULT;
dd.BindFlags = D3D11_BIND_DEPTH_STENCIL;
if (g_pDepthStencilBuffer == NULL)
g_pd3dDevice->CreateTexture2D(&dd, NULL, &g_pDepthStencilBuffer);
if (g_pDepthStencilBuffer != NULL)
{
D3D11_DEPTH_STENCIL_VIEW_DESC dsvd = {};
dsvd.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
dsvd.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
g_pd3dDevice->CreateDepthStencilView(g_pDepthStencilBuffer, &dsvd, &g_pDepthStencilView);
}
}
if (g_pRenderTargetView != NULL)
g_pImmediateContext->OMSetRenderTargets(1, &g_pRenderTargetView, g_pDepthStencilView);
ui.updateRenderTargets(g_pRenderTargetView, g_pDepthStencilView);
// If the surviving swap chain is the OLD one, dims are unchanged.
// If it's the NEW one (partial failure after swap), update to new dims.
if (g_pSwapChain != pOldSwapChain)
{
g_rScreenWidth = recW;
g_rScreenHeight = recH;
ui.updateScreenSize(recW, recH);
}
FlipTestLog("[ResizeD3D] FAILED path: recovered views at %dx%d\n", g_rScreenWidth, g_rScreenHeight);
}
gdraw_D3D11_PostReset();
gdraw_D3D11_SetRendertargetSize(g_rScreenWidth, g_rScreenHeight);
if (success)
IggyFlushInstalledFonts();
RenderManager.Resume();
if (success)
PostProcesser::GetInstance().Init();
FlipTestLog("[ResizeD3D] returning %s (final backbuffer %dx%d)\n",
success ? "success" : "FAILURE", g_rScreenWidth, g_rScreenHeight);
return success;
}
//--------------------------------------------------------------------------------------
// Toggle borderless fullscreen
//--------------------------------------------------------------------------------------
void ToggleFullscreen()
{
const DWORD dwStyle = GetWindowLong(g_hWnd, GWL_STYLE);
if (!g_isFullscreen)
{
MONITORINFO mi = { sizeof(mi) };
if (GetWindowPlacement(g_hWnd, &g_wpPrev) &&
GetMonitorInfo(MonitorFromWindow(g_hWnd, MONITOR_DEFAULTTOPRIMARY), &mi))
{
SetWindowLong(g_hWnd, GWL_STYLE, dwStyle & ~WS_OVERLAPPEDWINDOW);
SetWindowPos(g_hWnd, HWND_TOP,
mi.rcMonitor.left, mi.rcMonitor.top,
mi.rcMonitor.right - mi.rcMonitor.left,
mi.rcMonitor.bottom - mi.rcMonitor.top,
SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
}
}
else
{
SetWindowLong(g_hWnd, GWL_STYLE, dwStyle | WS_OVERLAPPEDWINDOW);
SetWindowPlacement(g_hWnd, &g_wpPrev);
SetWindowPos(g_hWnd, nullptr, 0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
}
g_isFullscreen = !g_isFullscreen;
SaveFullscreenOption(g_isFullscreen);
if (g_KBMInput.IsWindowFocused())
g_KBMInput.SetWindowFocused(true);
}
// Called from UI thread — defers the actual transition to the main game loop
void SetExclusiveFullscreen(bool enabled)
{
if (enabled == g_isFullscreen)
return;
g_bPendingExclusiveFullscreen = true;
g_bPendingExclusiveFullscreenValue = enabled;
}
// Uses borderless fullscreen (ToggleFullscreen) rather than DXGI SetFullscreenState.
// True DXGI exclusive fullscreen is blocked by the 4J Renderer holding hidden
// backbuffer references that prevent ResizeBuffers.
static void ApplyExclusiveFullscreen(bool enabled)
{
// Toggle into/out of borderless fullscreen if state doesn't match
if (enabled && !g_isFullscreen)
ToggleFullscreen();
else if (!enabled && g_isFullscreen)
ToggleFullscreen();
}
//--------------------------------------------------------------------------------------
// Clean up the objects we've created
//--------------------------------------------------------------------------------------
void CleanupDevice()
{
if( g_pImmediateContext ) g_pImmediateContext->ClearState();
if( g_pDepthStencilView ) g_pDepthStencilView->Release();
if( g_pDepthStencilBuffer ) g_pDepthStencilBuffer->Release();
if( g_pRenderTargetView ) g_pRenderTargetView->Release();
if( g_pSwapChain ) g_pSwapChain->Release();
if( g_pImmediateContext ) g_pImmediateContext->Release();
if( g_pd3dDevice ) g_pd3dDevice->Release();
}
static Minecraft* InitialiseMinecraftRuntime()
{
app.loadMediaArchive();
RenderManager.Initialise(g_pd3dDevice, g_pSwapChain);
app.loadStringTable();
ui.init(g_pd3dDevice, g_pImmediateContext, g_pRenderTargetView, g_pDepthStencilView, g_rScreenWidth, g_rScreenHeight);
InputManager.Initialise(1, 3, MINECRAFT_ACTION_MAX, ACTION_MAX_MENU);
g_KBMInput.Init();
DefineActions();
InputManager.SetJoypadMapVal(0, 0);
InputManager.SetKeyRepeatRate(0.3f, 0.2f);
ProfileManager.Initialise(TITLEID_MINECRAFT,
app.m_dwOfferID,
PROFILE_VERSION_10,
NUM_PROFILE_VALUES,
NUM_PROFILE_SETTINGS,
dwProfileSettingsA,
app.GAME_DEFINED_PROFILE_DATA_BYTES * XUSER_MAX_COUNT,
&app.uiGameDefinedDataChangedBitmask
);
ProfileManager.SetDefaultOptionsCallback(&CConsoleMinecraftApp::DefaultOptionsCallback, (LPVOID)&app);
g_NetworkManager.Initialise();
for (int i = 0; i < MINECRAFT_NET_MAX_PLAYERS; i++)
{
IQNet::m_player[i].m_smallId = static_cast<BYTE>(i);
IQNet::m_player[i].m_isRemote = false;
IQNet::m_player[i].m_isHostPlayer = (i == 0);
swprintf_s(IQNet::m_player[i].m_gamertag, 32, L"Player%d", i);
}
wcscpy_s(IQNet::m_player[0].m_gamertag, 32, g_Win64UsernameW);
WinsockNetLayer::Initialize();
ProfileManager.SetDebugFullOverride(true);
Tesselator::CreateNewThreadStorage(1024 * 1024);
AABB::CreateNewThreadStorage();
Vec3::CreateNewThreadStorage();
IntCache::CreateNewThreadStorage();
Compression::CreateNewThreadStorage();
OldChunkStorage::CreateNewThreadStorage();
Level::enableLightingCache();
Tile::CreateNewThreadStorage();
Minecraft::main();
Minecraft* pMinecraft = Minecraft::GetInstance();
if (pMinecraft == nullptr)
return nullptr;
app.InitGameSettings();
app.InitialiseTips();
return pMinecraft;
}
int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPTSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// 4J-Win64: set CWD to exe dir so asset paths resolve correctly
{
char szExeDir[MAX_PATH] = {};
GetModuleFileNameA(nullptr, szExeDir, MAX_PATH);
char *pSlash = strrchr(szExeDir, '\\');
if (pSlash) { *(pSlash + 1) = '\0'; SetCurrentDirectoryA(szExeDir); }
}
// Declare DPI awareness so GetSystemMetrics returns physical pixels
SetProcessDPIAware();
// Use the native monitor resolution for the window and swap chain,
// but keep g_iScreenWidth/Height at 1920x1080 for logical resolution
// (SWF selection, ortho projection, game logic). The real window
// dimensions are tracked by g_rScreenWidth/g_rScreenHeight.
g_rScreenWidth = GetSystemMetrics(SM_CXSCREEN);
g_rScreenHeight = GetSystemMetrics(SM_CYSCREEN);
// Load username from username.txt
char exePath[MAX_PATH] = {};
GetModuleFileNameA(nullptr, exePath, MAX_PATH);
char *lastSlash = strrchr(exePath, '\\');
if (lastSlash)
{
*(lastSlash + 1) = '\0';
}
char filePath[MAX_PATH] = {};
_snprintf_s(filePath, sizeof(filePath), _TRUNCATE, "%susername.txt", exePath);
FILE *f = nullptr;
if (fopen_s(&f, filePath, "r") == 0 && f)
{
char buf[128] = {};
if (fgets(buf, sizeof(buf), f))
{
int len = static_cast<int>(strlen(buf));
while (len > 0 && (buf[len - 1] == '\n' || buf[len - 1] == '\r' || buf[len - 1] == ' '))
{
buf[--len] = '\0';
}
if (len > 0)
{
strncpy_s(g_Win64Username, sizeof(g_Win64Username), buf, _TRUNCATE);
}
}
fclose(f);
}
// Load stuff from launch options, including username
const Win64LaunchOptions launchOptions = ParseLaunchOptions();
ApplyScreenMode(launchOptions.screenMode);
// Ensure uid.dat exists from startup (before any multiplayer/login path).
Win64Xuid::ResolvePersistentXuid();
// If no username, let's fall back
if (g_Win64Username[0] == 0)
{
// Default username will be "Player"
strncpy_s(g_Win64Username, sizeof(g_Win64Username), "Player", _TRUNCATE);
}
MultiByteToWideChar(CP_ACP, 0, g_Win64Username, -1, g_Win64UsernameW, 17);
// convert servers.txt to servers.db
if (GetFileAttributesA("servers.txt") != INVALID_FILE_ATTRIBUTES &&
GetFileAttributesA("servers.db") == INVALID_FILE_ATTRIBUTES)
{
FILE* txtFile = nullptr;
if (fopen_s(&txtFile, "servers.txt", "r") == 0 && txtFile)
{
struct MigEntry { std::string ip; uint16_t port; std::string name; };
std::vector<MigEntry> migEntries;
char line[512];
while (fgets(line, sizeof(line), txtFile))
{
int l = (int)strlen(line);
while (l > 0 && (line[l - 1] == '\n' || line[l - 1] == '\r' || line[l - 1] == ' '))
line[--l] = '\0';
if (l == 0) continue;
std::string srvIP = line;
if (!fgets(line, sizeof(line), txtFile)) break;
l = (int)strlen(line);
while (l > 0 && (line[l - 1] == '\n' || line[l - 1] == '\r' || line[l - 1] == ' '))
line[--l] = '\0';
uint16_t srvPort = (uint16_t)atoi(line);
std::string srvName;
if (fgets(line, sizeof(line), txtFile))
{
l = (int)strlen(line);
while (l > 0 && (line[l - 1] == '\n' || line[l - 1] == '\r' || line[l - 1] == ' '))
line[--l] = '\0';
srvName = line;
}
if (!srvIP.empty() && srvPort > 0)
migEntries.push_back({srvIP, srvPort, srvName});
}
fclose(txtFile);
if (!migEntries.empty())
{
FILE* dbFile = nullptr;
if (fopen_s(&dbFile, "servers.db", "wb") == 0 && dbFile)
{
fwrite("MCSV", 1, 4, dbFile);
uint32_t ver = 1;
uint32_t cnt = (uint32_t)migEntries.size();
fwrite(&ver, sizeof(uint32_t), 1, dbFile);
fwrite(&cnt, sizeof(uint32_t), 1, dbFile);
for (size_t i = 0; i < migEntries.size(); i++)
{
uint16_t ipLen = (uint16_t)migEntries[i].ip.length();
fwrite(&ipLen, sizeof(uint16_t), 1, dbFile);
fwrite(migEntries[i].ip.c_str(), 1, ipLen, dbFile);
fwrite(&migEntries[i].port, sizeof(uint16_t), 1, dbFile);
uint16_t nameLen = (uint16_t)migEntries[i].name.length();
fwrite(&nameLen, sizeof(uint16_t), 1, dbFile);
fwrite(migEntries[i].name.c_str(), 1, nameLen, dbFile);
}
fclose(dbFile);
}
}
}
}
// Initialize global strings
MyRegisterClass(hInstance);
// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
hMyInst=hInstance;
if( FAILED( InitDevice() ) )
{
CleanupDevice();
return 0;
}
// Restore fullscreen state from previous session
if (LoadFullscreenOption() && !g_isFullscreen || launchOptions.fullscreen)
{
ToggleFullscreen();
}
#if 0
// Main message loop
MSG msg = {0};
while( WM_QUIT != msg.message )
{
if( PeekMessage( &msg, nullptr, 0, 0, PM_REMOVE ) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
else
{
Render();
}
}
return (int) msg.wParam;
#endif
static bool bTrialTimerDisplayed=true;
#ifdef MEMORY_TRACKING
ResetMem();
MEMORYSTATUS memStat;
GlobalMemoryStatus(&memStat);
printf("RESETMEM start: Avail. phys %d\n",memStat.dwAvailPhys/(1024*1024));
#endif
#if 0
// Initialize D3D
hr = InitD3D( &pDevice, &d3dpp );
g_pD3DDevice = pDevice;
if( FAILED(hr) )
{
app.DebugPrintf
( "Failed initializing D3D.\n" );
return -1;
}
// Initialize the application, assuming sharing of the d3d interface.
hr = app.InitShared( pDevice, &d3dpp,
XuiPNGTextureLoader );
if ( FAILED(hr) )
{
app.DebugPrintf
( "Failed initializing application.\n" );
return -1;
}
#endif
Minecraft *pMinecraft = InitialiseMinecraftRuntime();
if (pMinecraft == nullptr)
{
CleanupDevice();
return 1;
}
g_bResizeReady = true;
//app.TemporaryCreateGameStart();
//Sleep(10000);
#if 0
// Intro loop ?
while(app.IntroRunning())
{
ProfileManager.Tick();
// Tick XUI
app.RunFrame();
// 4J : WESTY : Added to ensure we always have clear background for intro.
RenderManager.SetClearColour(D3DCOLOR_RGBA(0,0,0,255));
RenderManager.Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Render XUI
hr = app.Render();
// Present the frame.
RenderManager.Present();
// Update XUI Timers
hr = XuiTimersRun();
}
#endif
MSG msg = {0};
while( WM_QUIT != msg.message && !app.m_bShutdown)
{
g_KBMInput.Tick();
while( PeekMessage( &msg, nullptr, 0, 0, PM_REMOVE ) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
if (msg.message == WM_QUIT) break;
}
if (msg.message == WM_QUIT) break;
// When the window is minimized (e.g. "Show Desktop"), skip rendering entirely
// to avoid pegging the GPU at 100% presenting to a non-visible swap chain.
if (IsIconic(g_hWnd))
{
Sleep(100);
continue;
}
const float* clearColor = app.GetGameStarted() ? kClearColorBlack : kClearColorWhite;
RenderManager.SetClearColour(clearColor);
RenderManager.StartFrame();
if (!app.GetGameStarted())
{
RenderManager.SetClearColour(kClearColorWhite); // set intro scene background to white
RenderManager.Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
#if 0
if(pMinecraft->soundEngine->isStreamingWavebankReady() &&
!pMinecraft->soundEngine->isPlayingStreamingGameMusic() &&
!pMinecraft->soundEngine->isPlayingStreamingCDMusic() )
{
// play some music in the menus
pMinecraft->soundEngine->playStreaming(L"", 0, 0, 0, 0, 0, false);
}
#endif
// static bool bPlay=false;
// if(bPlay)
// {
// bPlay=false;
// app.audio.PlaySound();
// }
app.UpdateTime();
PIXBeginNamedEvent(0,"Input manager tick");
InputManager.Tick();
// Detect KBM vs controller input mode
if (InputManager.IsPadConnected(0))
{
const bool controllerUsed = InputManager.ButtonPressed(0) ||
InputManager.GetJoypadStick_LX(0, false) != 0.0f ||
InputManager.GetJoypadStick_LY(0, false) != 0.0f ||
InputManager.GetJoypadStick_RX(0, false) != 0.0f ||
InputManager.GetJoypadStick_RY(0, false) != 0.0f;
if (controllerUsed)
g_KBMInput.SetKBMActive(false);
else if (g_KBMInput.HasAnyInput())
g_KBMInput.SetKBMActive(true);
}
else
{
g_KBMInput.SetKBMActive(true);
}
if (!g_KBMInput.IsMouseGrabbed())
{
if (!g_KBMInput.IsKBMActive())
g_KBMInput.SetCursorHiddenForUI(true);
else if (!g_KBMInput.IsScreenCursorHidden())
g_KBMInput.SetCursorHiddenForUI(false);
}
PIXEndNamedEvent();
PIXBeginNamedEvent(0,"Profile manager tick");
// ProfileManager.Tick();
PIXEndNamedEvent();
PIXBeginNamedEvent(0,"Storage manager tick");
StorageManager.Tick();
PIXEndNamedEvent();
PIXBeginNamedEvent(0,"Render manager tick");
RenderManager.Tick();
PIXEndNamedEvent();
// Tick the social networking manager.
PIXBeginNamedEvent(0,"Social network manager tick");
// CSocialManager::Instance()->Tick();
PIXEndNamedEvent();
// Tick sentient.
PIXBeginNamedEvent(0,"Sentient tick");
MemSect(37);
// SentientManager.Tick();
MemSect(0);
PIXEndNamedEvent();
PIXBeginNamedEvent(0,"Network manager do work #1");
g_NetworkManager.DoWork();
PIXEndNamedEvent();
// LeaderboardManager::Instance()->Tick();
// Render game graphics.
if(app.GetGameStarted())
{
pMinecraft->applyFrameMouseLook(); // Per-frame mouse look (before ticks + render)
pMinecraft->run_middle();
app.SetAppPaused( g_NetworkManager.IsLocalGame() && g_NetworkManager.GetPlayerCount() == 1 && ui.IsPauseMenuDisplayed(ProfileManager.GetPrimaryPad()) );
}
else
{
MemSect(28);
pMinecraft->soundEngine->tick(nullptr, 0.0f);
MemSect(0);
pMinecraft->textures->tick(true,false);
IntCache::Reset();
if( app.GetReallyChangingSessionType() )
{
pMinecraft->tickAllConnections(); // Added to stop timing out when we are waiting after converting to an offline game
}
}
pMinecraft->soundEngine->playMusicTick();
#ifdef MEMORY_TRACKING
static bool bResetMemTrack = false;
static bool bDumpMemTrack = false;
MemPixStuff();
if( bResetMemTrack )
{
ResetMem();
MEMORYSTATUS memStat;
GlobalMemoryStatus(&memStat);
printf("RESETMEM: Avail. phys %d\n",memStat.dwAvailPhys/(1024*1024));
bResetMemTrack = false;
}
if( bDumpMemTrack )
{
DumpMem();
bDumpMemTrack = false;
MEMORYSTATUS memStat;
GlobalMemoryStatus(&memStat);
printf("DUMPMEM: Avail. phys %d\n",memStat.dwAvailPhys/(1024*1024));
printf("Renderer used: %d\n",RenderManager.CBuffSize(-1));
}
#endif
#if 0
static bool bDumpTextureUsage = false;
if( bDumpTextureUsage )
{
RenderManager.TextureGetStats();
bDumpTextureUsage = false;
}
#endif
ui.tick();
ui.render();
pMinecraft->gameRenderer->ApplyGammaPostProcess();
#if 0
app.HandleButtonPresses();
// store the minecraft renderstates, and re-set them after the xui render
GetRenderAndSamplerStates(pDevice,RenderStateA,SamplerStateA);
// Tick XUI
PIXBeginNamedEvent(0,"Xui running");
app.RunFrame();
PIXEndNamedEvent();
// Render XUI
PIXBeginNamedEvent(0,"XUI render");
MemSect(7);
hr = app.Render();
MemSect(0);
GetRenderAndSamplerStates(pDevice,RenderStateA2,SamplerStateA2);
PIXEndNamedEvent();
for(int i=0;i<8;i++)
{
if(RenderStateA2[i]!=RenderStateA[i])
{
//printf("Reseting RenderStateA[%d] after a XUI render\n",i);
pDevice->SetRenderState(RenderStateModes[i],RenderStateA[i]);
}
}
for(int i=0;i<5;i++)
{
if(SamplerStateA2[i]!=SamplerStateA[i])
{
//printf("Reseting SamplerStateA[%d] after a XUI render\n",i);
pDevice->SetSamplerState(0,SamplerStateModes[i],SamplerStateA[i]);
}
}
RenderManager.Set_matrixDirty();
#endif
// Present the frame.
// RenderManager.Present() hardcodes SyncInterval=1 internally.
// When VSync is off, bypass it and call the swap chain directly
// with SyncInterval=0 and DXGI_PRESENT_ALLOW_TEARING so DWM lets the
// frame tear instead of VSync-locking us to the refresh rate.
if (!g_bVSync && g_pSwapChain)
{
UINT presentFlags = g_bTearingSupported ? DXGI_PRESENT_ALLOW_TEARING : 0;
HRESULT hrPresent = g_pSwapChain->Present(0, presentFlags);
// If the direct Present fails (e.g. during fullscreen transition),
// fall back to the library's VSync'd Present for this frame.
if (FAILED(hrPresent))
RenderManager.Present();
}
else
{
RenderManager.Present();
}
ui.CheckMenuDisplayed();
// Update mouse grab: grab when in-game and no menu is open
{
static bool altToggleSuppressCapture = false;
const bool shouldCapture = app.GetGameStarted() && !ui.GetMenuDisplayed(0) && pMinecraft->screen == nullptr;
// Left Alt key toggles capture on/off for debugging
if (g_KBMInput.IsKeyPressed(VK_LMENU) || g_KBMInput.IsKeyPressed(VK_RMENU))
{
if (g_KBMInput.IsMouseGrabbed()) { g_KBMInput.SetMouseGrabbed(false); altToggleSuppressCapture = true; }
else if (shouldCapture) { g_KBMInput.SetMouseGrabbed(true); altToggleSuppressCapture = false; }
}
else if (!shouldCapture)
{
if (g_KBMInput.IsMouseGrabbed()) g_KBMInput.SetMouseGrabbed(false);
altToggleSuppressCapture = false;
}
else if (shouldCapture && !g_KBMInput.IsMouseGrabbed() && GetFocus() == g_hWnd && !altToggleSuppressCapture)
{
g_KBMInput.SetMouseGrabbed(true);
}
}
// F2 takes a screenshot (works in any context)
if (g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_SCREENSHOT))
{
wstring filename;
if (TakeScreenshot(filename))
{
if (pMinecraft->gui && pMinecraft->player)
{
wstring msg = L"Saved screenshot to " + filename;
pMinecraft->gui->addMessage(msg, ProfileManager.GetPrimaryPad());
}
}
}
// F1 toggles the HUD
if (g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_TOGGLE_HUD))
{
const int primaryPad = ProfileManager.GetPrimaryPad();
const unsigned char displayHud = app.GetGameSettings(primaryPad, eGameSetting_DisplayHUD);
app.SetGameSettings(primaryPad, eGameSetting_DisplayHUD, displayHud ? 0 : 1);
app.SetGameSettings(primaryPad, eGameSetting_DisplayHand, displayHud ? 0 : 1);
}
// F3 toggles onscreen debug info
if (g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_DEBUG_INFO)) f3ComboUsed = false;
// f3 combo
if (g_KBMInput.IsKeyDown(KeyboardMouseInput::KEY_DEBUG_INFO))
{
switch (g_KBMInput.GetPressedKey())
{
// advanced tooltips
case 'H':
if (pMinecraft->options && app.GetGameStarted())
{
pMinecraft->options->advancedTooltips = !pMinecraft->options->advancedTooltips;
pMinecraft->options->save();
const wstring msg = wstring(L"Advanced tooltips: ") + (pMinecraft->options->advancedTooltips ? L"shown" : L"hidden");
const int primaryPad = ProfileManager.GetPrimaryPad();
if (pMinecraft->gui) pMinecraft->gui->addMessage(msg, primaryPad);
f3ComboUsed = true;
}
break;
}
}
// no combo
if (g_KBMInput.IsKeyReleased(KeyboardMouseInput::KEY_DEBUG_INFO) && !f3ComboUsed)
if (pMinecraft->options)
pMinecraft->options->renderDebug = !pMinecraft->options->renderDebug;
#ifdef _DEBUG_MENUS_ENABLED
// F6 Open debug console
if (g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_DEBUG_CONSOLE))
{
static bool s_debugConsole = false;
s_debugConsole = !s_debugConsole;
ui.ShowUIDebugConsole(s_debugConsole);
}
#endif
// toggle fullscreen
if (g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_FULLSCREEN))
{
ToggleFullscreen();
app.SetGameSettings(ProfileManager.GetPrimaryPad(), eGameSetting_ExclusiveFullscreen, g_isFullscreen ? 1 : 0);
}
// Apply deferred exclusive fullscreen toggle
if (g_bPendingExclusiveFullscreen)
{
g_bPendingExclusiveFullscreen = false;
ApplyExclusiveFullscreen(g_bPendingExclusiveFullscreenValue);
}
// TAB opens game info menu. - Vvis :3 - Updated by detectiveren
if (g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_HOST_SETTINGS) && !ui.GetMenuDisplayed(0))
{
if (Minecraft* pMinecraft = Minecraft::GetInstance())
{
{
ui.NavigateToScene(0, eUIScene_InGameInfoMenu);
}
}
}
// Open chat
if (g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_CHAT) && app.GetGameStarted() && !ui.GetMenuDisplayed(0) && pMinecraft->screen == NULL)
{
g_KBMInput.ClearCharBuffer();
pMinecraft->setScreen(new ChatScreen());
SetFocus(g_hWnd);
}
#if 0
// has the game defined profile data been changed (by a profile load)
if(app.uiGameDefinedDataChangedBitmask!=0)
{
void *pData;
for(int i=0;i<XUSER_MAX_COUNT;i++)
{
if(app.uiGameDefinedDataChangedBitmask&(1<<i))
{\
// It has - game needs to update its values with the data from the profile
pData=ProfileManager.GetGameDefinedProfileData(i);
// reset the changed flag
app.ClearGameSettingsChangedFlag(i);
app.DebugPrintf("*** - APPLYING GAME SETTINGS CHANGE for pad %d\n",i);
app.ApplyGameSettingsChanged(i);
#ifdef _DEBUG_MENUS_ENABLED
if(app.DebugSettingsOn())
{
app.ActionDebugMask(i);
}
else
{
// force debug mask off
app.ActionDebugMask(i,true);
}
#endif
// clear the stats first - there could have beena signout and sign back in in the menus
// need to clear the player stats - can't assume it'll be done in setlevel - we may not be in the game
pMinecraft->stats[ i ]->clear();
pMinecraft->stats[i]->parse(pData);
}
}
// Check to see if we can post to social networks.
CSocialManager::Instance()->RefreshPostingCapability();
// clear the flag
app.uiGameDefinedDataChangedBitmask=0;
// Check if any profile write are needed
app.CheckGameSettingsChanged();
}
PIXEndNamedEvent();
app.TickDLCOffersRetrieved();
app.TickTMSPPFilesRetrieved();
PIXBeginNamedEvent(0,"Network manager do work #2");
g_NetworkManager.DoWork();
PIXEndNamedEvent();
PIXBeginNamedEvent(0,"Misc extra xui");
// Update XUI Timers
hr = XuiTimersRun();
#endif
// Any threading type things to deal with from the xui side?
app.HandleXuiActions();
#if 0
PIXEndNamedEvent();
#endif
// 4J-PB - Update the trial timer display if we are in the trial version
if(!ProfileManager.IsFullVersion())
{
// display the trial timer
if(app.GetGameStarted())
{
// 4J-PB - if the game is paused, add the elapsed time to the trial timer count so it doesn't tick down
if(app.IsAppPaused())
{
app.UpdateTrialPausedTimer();
}
ui.UpdateTrialTimer(ProfileManager.GetPrimaryPad());
}
}
else
{
// need to turn off the trial timer if it was on , and we've unlocked the full version
if(bTrialTimerDisplayed)
{
ui.ShowTrialTimer(false);
bTrialTimerDisplayed=false;
}
}
// Fix for #7318 - Title crashes after short soak in the leaderboards menu
// A memory leak was caused because the icon renderer kept creating new Vec3's because the pool wasn't reset
Vec3::resetPool();
}
// Free resources, unregister custom classes, and exit.
// app.Uninit();
g_pd3dDevice->Release();
}
#ifdef MEMORY_TRACKING
int totalAllocGen = 0;
unordered_map<int,int> allocCounts;
bool trackEnable = false;
bool trackStarted = false;
volatile size_t sizeCheckMin = 1160;
volatile size_t sizeCheckMax = 1160;
volatile int sectCheck = 48;
CRITICAL_SECTION memCS;
DWORD tlsIdx;
LPVOID XMemAlloc(SIZE_T dwSize, DWORD dwAllocAttributes)
{
if( !trackStarted )
{
void *p = XMemAllocDefault(dwSize,dwAllocAttributes);
size_t realSize = XMemSizeDefault(p, dwAllocAttributes);
totalAllocGen += realSize;
return p;
}
EnterCriticalSection(&memCS);
void *p=XMemAllocDefault(dwSize + 16,dwAllocAttributes);
size_t realSize = XMemSizeDefault(p,dwAllocAttributes) - 16;
if( trackEnable )
{
#if 1
int sect = ((int) TlsGetValue(tlsIdx)) & 0x3f;
*(((unsigned char *)p)+realSize) = sect;
if( ( realSize >= sizeCheckMin ) && ( realSize <= sizeCheckMax ) && ( ( sect == sectCheck ) || ( sectCheck == -1 ) ) )
{
app.DebugPrintf("Found one\n");
}
#endif
if( p )
{
totalAllocGen += realSize;
trackEnable = false;
int key = ( sect << 26 ) | realSize;
int oldCount = allocCounts[key];
allocCounts[key] = oldCount + 1;
trackEnable = true;
}
}
LeaveCriticalSection(&memCS);
return p;
}
void* operator new (size_t size)
{
return (unsigned char *)XMemAlloc(size,MAKE_XALLOC_ATTRIBUTES(0,FALSE,TRUE,FALSE,0,XALLOC_PHYSICAL_ALIGNMENT_DEFAULT,XALLOC_MEMPROTECT_READWRITE,FALSE,XALLOC_MEMTYPE_HEAP));
}
void operator delete (void *p)
{
XMemFree(p,MAKE_XALLOC_ATTRIBUTES(0,FALSE,TRUE,FALSE,0,XALLOC_PHYSICAL_ALIGNMENT_DEFAULT,XALLOC_MEMPROTECT_READWRITE,FALSE,XALLOC_MEMTYPE_HEAP));
}
void WINAPI XMemFree(PVOID pAddress, DWORD dwAllocAttributes)
{
bool special = false;
if( dwAllocAttributes == 0 )
{
dwAllocAttributes = MAKE_XALLOC_ATTRIBUTES(0,FALSE,TRUE,FALSE,0,XALLOC_PHYSICAL_ALIGNMENT_DEFAULT,XALLOC_MEMPROTECT_READWRITE,FALSE,XALLOC_MEMTYPE_HEAP);
special = true;
}
if(!trackStarted )
{
size_t realSize = XMemSizeDefault(pAddress, dwAllocAttributes);
XMemFreeDefault(pAddress, dwAllocAttributes);
totalAllocGen -= realSize;
return;
}
EnterCriticalSection(&memCS);
if( pAddress )
{
size_t realSize = XMemSizeDefault(pAddress, dwAllocAttributes) - 16;
if(trackEnable)
{
int sect = *(((unsigned char *)pAddress)+realSize);
totalAllocGen -= realSize;
trackEnable = false;
int key = ( sect << 26 ) | realSize;
int oldCount = allocCounts[key];
allocCounts[key] = oldCount - 1;
trackEnable = true;
}
XMemFreeDefault(pAddress, dwAllocAttributes);
}
LeaveCriticalSection(&memCS);
}
SIZE_T WINAPI XMemSize(
PVOID pAddress,
DWORD dwAllocAttributes
)
{
if( trackStarted )
{
return XMemSizeDefault(pAddress, dwAllocAttributes) - 16;
}
else
{
return XMemSizeDefault(pAddress, dwAllocAttributes);
}
}
void DumpMem()
{
int totalLeak = 0;
for( auto it = allocCounts.begin(); it != allocCounts.end(); it++ )
{
if(it->second > 0 )
{
app.DebugPrintf("%d %d %d %d\n",( it->first >> 26 ) & 0x3f,it->first & 0x03ffffff, it->second, (it->first & 0x03ffffff) * it->second);
totalLeak += ( it->first & 0x03ffffff ) * it->second;
}
}
app.DebugPrintf("Total %d\n",totalLeak);
}
void ResetMem()
{
if( !trackStarted )
{
trackEnable = true;
trackStarted = true;
totalAllocGen = 0;
InitializeCriticalSection(&memCS);
tlsIdx = TlsAlloc();
}
EnterCriticalSection(&memCS);
trackEnable = false;
allocCounts.clear();
trackEnable = true;
LeaveCriticalSection(&memCS);
}
void MemSect(int section)
{
unsigned int value = (unsigned int)TlsGetValue(tlsIdx);
if( section == 0 ) // pop
{
value = (value >> 6) & 0x03ffffff;
}
else
{
value = (value << 6) | section;
}
TlsSetValue(tlsIdx, (LPVOID)value);
}
void MemPixStuff()
{
const int MAX_SECT = 46;
int totals[MAX_SECT] = {0};
for( auto it = allocCounts.begin(); it != allocCounts.end(); it++ )
{
if(it->second > 0 )
{
int sect = ( it->first >> 26 ) & 0x3f;
int bytes = it->first & 0x03ffffff;
totals[sect] += bytes * it->second;
}
}
unsigned int allSectsTotal = 0;
for( int i = 0; i < MAX_SECT; i++ )
{
allSectsTotal += totals[i];
PIXAddNamedCounter(((float)totals[i])/1024.0f,"MemSect%d",i);
}
PIXAddNamedCounter(((float)allSectsTotal)/(4096.0f),"MemSect total pages");
}
#endif