refactor: use thread_local in OldChunkStorage, FireworksRecipe, Level, Entity

This commit is contained in:
Tropical 2026-03-25 14:13:00 -05:00
parent 03f62dcb9e
commit 625ce97385
9 changed files with 44 additions and 150 deletions

View file

@ -27,11 +27,11 @@ int normal;
thread_local Tesselator* Tesselator::m_threadInstance = nullptr;
Tesselator* Tesselator::getInstance() {
return m_threadinstance;
return m_threadInstance;
}
void Tesselator::CreateNewThreadStorage(int bytes) {
Tesselator::m_threadinstance = new Tesselator(bytes / 4);
Tesselator::m_threadInstance = new Tesselator(bytes / 4);
}
// she tessalate my vertices till i render

View file

@ -1,6 +1,6 @@
#pragma once
class DispenseItemBehavior;
#include "DispenseItemBehavior.h"
class BehaviorRegistry {
private:

View file

@ -26,40 +26,12 @@
#include "../../Minecraft.Client/Level/ServerLevel.h"
#include "../../Minecraft.Client/Network/PlayerList.h"
namespace {
#if defined(_WIN32)
inline void* EntityTlsGetValue(Entity::TlsKey key) { return TlsGetValue(key); }
inline void EntityTlsSetValue(Entity::TlsKey key, void* value) {
TlsSetValue(key, value);
}
#else
pthread_key_t CreateEntityTlsKey() {
pthread_key_t key;
const int result = pthread_key_create(&key, nullptr);
assert(result == 0);
return key;
}
inline void* EntityTlsGetValue(pthread_key_t key) {
return pthread_getspecific(key);
}
inline void EntityTlsSetValue(pthread_key_t key, void* value) {
pthread_setspecific(key, value);
}
#endif
} // namespace
thread_local bool Entity::m_threadUseSmallIds = false;
const std::wstring Entity::RIDING_TAG = L"Riding";
int Entity::entityCounter =
2048; // 4J - changed initialiser to 2048, as we are using range 0 - 2047
// as special unique smaller ids for things that need network tracked
#if defined(_WIN32)
Entity::TlsKey Entity::tlsIdx = TlsAlloc();
#else
Entity::TlsKey Entity::tlsIdx = CreateEntityTlsKey();
#endif
// 4J - added getSmallId & freeSmallId methods
unsigned int Entity::entityIdUsedFlags[2048 / 32] = {0};
@ -82,7 +54,7 @@ int Entity::getSmallId() {
// telling the client that the entity has been removed After we have already
// re-used its Id and created a new entity. This ends up with newly created
// client-side entities being removed by accident, causing invisible mobs.
if (reinterpret_cast<std::intptr_t>(EntityTlsGetValue(tlsIdx)) != 0) {
if (m_threadUseSmallIds) {
MinecraftServer* server = MinecraftServer::getInstance();
if (server) {
// In some attempt to optimise this, flagEntitiesToBeRemoved most of
@ -157,13 +129,13 @@ void Entity::countFlagsForPIX() {
void Entity::resetSmallId() {
freeSmallId(entityId);
if (reinterpret_cast<std::intptr_t>(EntityTlsGetValue(tlsIdx)) != 0) {
if (m_threadUseSmallIds) {
entityId = getSmallId();
}
}
void Entity::freeSmallId(int index) {
if (reinterpret_cast<std::intptr_t>(EntityTlsGetValue(tlsIdx)) == 0)
if (!m_threadUseSmallIds)
return; // Don't do anything with small ids if this isn't the server
// thread
if (index >= 2048) return; // Don't do anything if this isn't a short id
@ -176,10 +148,7 @@ void Entity::freeSmallId(int index) {
entityIdWanderFlags[i] &= uiMask;
}
void Entity::useSmallIds() {
EntityTlsSetValue(tlsIdx,
reinterpret_cast<void*>(static_cast<std::intptr_t>(1)));
}
void Entity::useSmallIds() { m_threadUseSmallIds = true; }
// Things also added here to be able to manage the concept of a number of extra
// "wandering" entities - normally path finding entities aren't allowed to
@ -192,7 +161,7 @@ void Entity::useSmallIds() {
// Let the management system here know whether or not to consider this
// particular entity for some extra wandering
void Entity::considerForExtraWandering(bool enable) {
if (reinterpret_cast<std::intptr_t>(EntityTlsGetValue(tlsIdx)) == 0)
if (!m_threadUseSmallIds)
return; // Don't do anything with small ids if this isn't the server
// thread
if (entityId >= 2048) return; // Don't do anything if this isn't a short id
@ -211,7 +180,7 @@ void Entity::considerForExtraWandering(bool enable) {
// Should this entity do wandering in addition to what the java code would have
// done?
bool Entity::isExtraWanderingEnabled() {
if (reinterpret_cast<std::intptr_t>(EntityTlsGetValue(tlsIdx)) == 0)
if (!m_threadUseSmallIds)
return false; // Don't do anything with small ids if this isn't the
// server thread
if (entityId >= 2048)
@ -278,8 +247,7 @@ void Entity::_init(bool useSmallId, Level* level) {
// rest of the range is used for anything we don't need to track like this,
// currently particles. We only ever want to allocate this type of id from
// the server thread, so using thread local storage to isolate this.
if (useSmallId &&
reinterpret_cast<std::intptr_t>(EntityTlsGetValue(tlsIdx)) != 0) {
if (useSmallId && m_threadUseSmallIds) {
entityId = getSmallId();
} else {
entityId = Entity::entityCounter++;

View file

@ -6,9 +6,6 @@
#include "../Util/Vec3.h"
#include "../Util/Definitions.h"
#include <cstdint>
#if !defined(_WIN32)
#include <pthread.h>
#endif
class LivingEntity;
class LightningBolt;
@ -431,7 +428,8 @@ private:
static int extraWanderIds[EXTRA_WANDER_MAX];
static int extraWanderCount;
static int extraWanderTicks;
static TlsKey tlsIdx;
static thread_local bool m_threadUseSmallIds;
public:
static void tickExtraWandering();
static void countFlagsForPIX();

View file

@ -41,38 +41,6 @@
#include "../../Minecraft.Client/MinecraftServer.h"
#include <cstdint>
namespace {
#if defined(_WIN32)
inline void* LevelTlsGetValue(Level::TlsKey key) { return TlsGetValue(key); }
inline void LevelTlsSetValue(Level::TlsKey key, void* value) {
TlsSetValue(key, value);
}
#else
pthread_key_t CreateLevelTlsKey() {
pthread_key_t key;
pthread_key_create(&key, NULL);
return key;
}
inline void* LevelTlsGetValue(pthread_key_t key) {
return pthread_getspecific(key);
}
inline void LevelTlsSetValue(pthread_key_t key, void* value) {
pthread_setspecific(key, value);
}
#endif
} // namespace
#if defined(_WIN32)
Level::TlsKey Level::tlsIdx = TlsAlloc();
Level::TlsKey Level::tlsIdxLightCache = TlsAlloc();
#else
Level::TlsKey Level::tlsIdx = CreateLevelTlsKey();
Level::TlsKey Level::tlsIdxLightCache = CreateLevelTlsKey();
#endif
// 4J : WESTY : Added for time played stats.
#include "../Headers/net.minecraft.stats.h"
@ -122,20 +90,20 @@ Level::TlsKey Level::tlsIdxLightCache = CreateLevelTlsKey();
// W - lighting value requires write
#endif
thread_local bool Level::m_threadInstaTick = false;
thread_local Level::lightCache_t* Level::m_threadLightCache = nullptr;
void Level::enableLightingCache() {
// Allocate 16K (needs 32K for large worlds) for a 16x16x16x4 byte cache of
// results, plus 128K required for toCheck array. Rounding up to 256 to keep
// as multiple of alignement - aligning to 128K boundary for possible cache
// locking.
void* cache = (unsigned char*)XPhysicalAlloc(
m_threadLightCache = (lightCache_t*)XPhysicalAlloc(
256 * 1024, MAXULONG_PTR, 128 * 1024, PAGE_READWRITE | MEM_LARGE_PAGES);
LevelTlsSetValue(tlsIdxLightCache, cache);
}
void Level::destroyLightingCache() {
lightCache_t* cache =
static_cast<lightCache_t*>(LevelTlsGetValue(tlsIdxLightCache));
XPhysicalFree(cache);
delete m_threadLightCache;
}
inline int GetIndex(int x, int y, int z) {
@ -524,13 +492,11 @@ void Level::flushCache(lightCache_t* cache, uint64_t cacheUse,
// 4J - added following 2 functions to move instaBuild flag from being a class
// member, to TLS
bool Level::getInstaTick() {
return reinterpret_cast<std::intptr_t>(LevelTlsGetValue(tlsIdx)) != 0;
return m_threadInstaTick;
}
void Level::setInstaTick(bool enable) {
void* value = 0;
if (enable) value = (void*)1;
LevelTlsSetValue(tlsIdx, value);
m_threadInstaTick = enable;
}
// 4J - added
@ -3177,8 +3143,7 @@ int Level::getExpectedLight(lightCache_t* cache, int x, int y, int z,
// this thread
void Level::checkLight(LightLayer::variety layer, int xc, int yc, int zc,
bool force, bool rootOnlyEmissive) {
lightCache_t* cache =
static_cast<lightCache_t*>(LevelTlsGetValue(tlsIdxLightCache));
lightCache_t* cache = m_threadLightCache;
uint64_t cacheUse = 0;
if (force) {

View file

@ -54,10 +54,10 @@ class GameRules;
class Level : public LevelSource {
public:
#if defined(_WIN32)
using TlsKey = std::uint32_t;
#ifdef _LARGE_WORLDS
using lightCache_t = uint64_t;
#else
using TlsKey = pthread_key_t;
using lightCache_t = unsigned int;
#endif
static const int MAX_TICK_TILES_PER_TICK = 1000;
@ -93,8 +93,8 @@ public:
// 4J - added, making instaTick flag use TLS so we can set it in the chunk
// rebuilding thread without upsetting the main game thread
static TlsKey tlsIdx;
static TlsKey tlsIdxLightCache;
static thread_local bool m_threadInstaTick;
static thread_local lightCache_t* m_threadLightCache;
static void enableLightingCache();
static void destroyLightingCache();
static bool getCacheTestEnabled();
@ -277,11 +277,6 @@ public:
void setBrightnessNoUpdateOnClient(LightLayer::variety layer, int x, int y,
int z, int brightness); // 4J added
#ifdef _LARGE_WORLDS
typedef uint64_t lightCache_t;
#else
typedef unsigned int lightCache_t;
#endif
inline void setBrightnessCached(lightCache_t* cache, uint64_t* cacheUse,
LightLayer::variety layer, int x, int y,
int z, int brightness);

View file

@ -8,40 +8,11 @@
#include "../../Headers/net.minecraft.world.level.storage.h"
#include "../../IO/Files/FileHeader.h"
#include "OldChunkStorage.h"
#if defined(_WIN32)
namespace {
inline void* OldChunkStorageTlsGetValue(OldChunkStorage::TlsKey key) {
return TlsGetValue(key);
}
inline void OldChunkStorageTlsSetValue(OldChunkStorage::TlsKey key,
void* value) {
TlsSetValue(key, value);
}
} // namespace
OldChunkStorage::TlsKey OldChunkStorage::tlsIdx = TlsAlloc();
#else
namespace {
pthread_key_t CreateOldChunkStorageTlsKey() {
pthread_key_t key;
const int result = pthread_key_create(&key, nullptr);
assert(result == 0);
return key;
}
inline void* OldChunkStorageTlsGetValue(pthread_key_t key) {
return pthread_getspecific(key);
}
inline void OldChunkStorageTlsSetValue(pthread_key_t key, void* value) {
pthread_setspecific(key, value);
}
} // namespace
OldChunkStorage::TlsKey OldChunkStorage::tlsIdx = CreateOldChunkStorageTlsKey();
#endif
OldChunkStorage::ThreadStorage* OldChunkStorage::tlsDefault = NULL;
thread_local OldChunkStorage::ThreadStorage* OldChunkStorage::m_threadStorage =
nullptr;
OldChunkStorage::ThreadStorage* OldChunkStorage::m_defaultThreadStorage =
nullptr;
OldChunkStorage::ThreadStorage::ThreadStorage() {
blockData = byteArray(Level::CHUNK_TILE_COUNT);
@ -59,22 +30,22 @@ OldChunkStorage::ThreadStorage::~ThreadStorage() {
void OldChunkStorage::CreateNewThreadStorage() {
ThreadStorage* tls = new ThreadStorage();
if (tlsDefault == NULL) {
tlsDefault = tls;
if (m_defaultThreadStorage == nullptr) {
m_defaultThreadStorage = tls;
}
OldChunkStorageTlsSetValue(tlsIdx, tls);
m_threadStorage = tls;
}
void OldChunkStorage::UseDefaultThreadStorage() {
OldChunkStorageTlsSetValue(tlsIdx, tlsDefault);
m_threadStorage = m_defaultThreadStorage;
}
void OldChunkStorage::ReleaseThreadStorage() {
ThreadStorage* tls =
static_cast<ThreadStorage*>(OldChunkStorageTlsGetValue(tlsIdx));
if (tls == tlsDefault) return;
delete tls;
if (m_threadStorage != m_defaultThreadStorage) {
delete m_threadStorage;
}
}
OldChunkStorage::OldChunkStorage(File dir, bool create) {
@ -348,8 +319,7 @@ void OldChunkStorage::save(LevelChunk* lc, Level* level, CompoundTag* tag) {
// 4J Stu - As we now save on multiple threads, the static data has been
// moved to TLS
ThreadStorage* tls =
static_cast<ThreadStorage*>(OldChunkStorageTlsGetValue(tlsIdx));
ThreadStorage* tls = m_threadStorage;
PIXBeginNamedEvent(0, "Getting block data");
// static byteArray blockData = byteArray(32768);

View file

@ -31,8 +31,8 @@ private:
ThreadStorage();
~ThreadStorage();
};
static TlsKey tlsIdx;
static ThreadStorage* tlsDefault;
static thread_local ThreadStorage* m_threadStorage;
static ThreadStorage* m_defaultThreadStorage;
public:
// Each new thread that needs to use Compression will need to call one of

View file

@ -216,16 +216,14 @@ bool FireworksRecipe::matches(std::shared_ptr<CraftingContainer> craftSlots,
std::shared_ptr<ItemInstance> FireworksRecipe::assemble(
std::shared_ptr<CraftingContainer> craftSlots) {
ThreadStorage* tls = (ThreadStorage*)TlsGetValue(tlsIdx);
return tls->resultItem->copy();
return m_threadStorage->resultItem->copy();
// return resultItem->copy();
}
int FireworksRecipe::size() { return 10; }
const ItemInstance* FireworksRecipe::getResultItem() {
ThreadStorage* tls = (ThreadStorage*)TlsGetValue(tlsIdx);
return tls->resultItem.get();
return m_threadStorage->resultItem.get();
// return resultItem.get();
}