diff --git a/Minecraft.Client/Windows64/4JLibs/inc/Render/Renderer.h b/Minecraft.Client/Windows64/4JLibs/inc/Render/Renderer.h index 66378bdf9..599ebda0a 100644 --- a/Minecraft.Client/Windows64/4JLibs/inc/Render/Renderer.h +++ b/Minecraft.Client/Windows64/4JLibs/inc/Render/Renderer.h @@ -46,8 +46,8 @@ SOFTWARE. #define THUMBNAIL_DOWNSAMPLE_QUALITY_3 3 // 128x128 #define THUMBNAIL_DOWNSAMPLE_TARGET 4 // 64x64 -#define NUM_COMMAND_HANDLES 0x800000 -#define MAX_COMMAND_BUFFERS 16000 +#define NUM_COMMAND_HANDLES 0x10000 +#define MAX_COMMAND_BUFFERS 4096 class Renderer { @@ -169,6 +169,7 @@ private: ID3D11SamplerState *GetManagedSamplerState(); void DeleteInternalBuffer(int index); Renderer::Context &getContext(); + void GrowCommandBufferArrays(); public: enum eTextureSamplerFlags @@ -471,12 +472,12 @@ public: BYTE reservedRendererByte1; BYTE paddingAfterRendererByte1[3]; DWORD reservedRendererDword1; - int16_t *m_vertexIdxToBufferIdx; - CommandBuffer **m_commandBuffers; - DirectX::XMMATRIX *m_commandMatrices; - int *m_bufferIdxToVertexIdx; - uint8_t *m_commandPrimitiveTypes; - uint8_t *m_commandVertexTypes; + std::vector m_vertexIdxToBufferIdx; // int16_t -> int, иначе переполнение при >32767 буферах + std::vector m_commandBuffers; + std::vector m_commandMatrices; + std::vector m_bufferIdxToVertexIdx; + std::vector m_commandPrimitiveTypes; + std::vector m_commandVertexTypes; DWORD m_currentCommandBuffer; DWORD m_numBuffersToDeallocate; std::unordered_map managedBlendStates; diff --git a/Minecraft.Client/Windows64/4JLibs/inc/Render/RendererCBuff.cpp b/Minecraft.Client/Windows64/4JLibs/inc/Render/RendererCBuff.cpp index 6a1ab183d..8bd0dc241 100644 --- a/Minecraft.Client/Windows64/4JLibs/inc/Render/RendererCBuff.cpp +++ b/Minecraft.Client/Windows64/4JLibs/inc/Render/RendererCBuff.cpp @@ -206,6 +206,9 @@ bool Renderer::CBuffCall(int index, bool full) return result; } +static constexpr int CBUFF_SLOT_FREE = -1; // слот свободен, CBuffCreate может занять +static constexpr int CBUFF_SLOT_RESERVED = -2; // слот зарезервирован, но буфер не записан + void Renderer::CBuffClear(int index) { EnterCriticalSection(&m_commandBufferCS); @@ -214,7 +217,7 @@ void Renderer::CBuffClear(int index) if (internalIndex >= 0) { DeleteInternalBuffer(internalIndex); - m_vertexIdxToBufferIdx[index] = static_cast(-2); + m_vertexIdxToBufferIdx[index] = CBUFF_SLOT_RESERVED; // -2, не -1 } LeaveCriticalSection(&m_commandBufferCS); @@ -224,28 +227,33 @@ int Renderer::CBuffCreate(int count) { EnterCriticalSection(&m_commandBufferCS); + // Если не хватает handle-слотов — расширяем + if (reservedRendererDword1 + count >= static_cast(m_vertexIdxToBufferIdx.size())) + { + const size_t newSize = (m_vertexIdxToBufferIdx.size() + count) * 2; + m_vertexIdxToBufferIdx.resize(newSize, -1); + } + int first = reservedRendererDword1; - if (first < NUM_COMMAND_HANDLES) + const int limit = static_cast(m_vertexIdxToBufferIdx.size()); + + if (first < limit) { int probe = first; int end = first + count; while (true) { - assert(first < NUM_COMMAND_HANDLES); + assert(first < limit); int cursor = probe; - while (cursor < end && cursor < NUM_COMMAND_HANDLES && m_vertexIdxToBufferIdx[cursor] == static_cast(-1)) - { + while (cursor < end && cursor < limit && m_vertexIdxToBufferIdx[cursor] == CBUFF_SLOT_FREE) ++cursor; - } if (cursor >= end) break; - ++first; - ++probe; - ++end; - if (first >= NUM_COMMAND_HANDLES || end > NUM_COMMAND_HANDLES) + ++first; ++probe; ++end; + if (first >= limit || end > limit) { first = -1; break; @@ -256,7 +264,7 @@ int Renderer::CBuffCreate(int count) { const int allocationEnd = first + count; for (int i = first; i < allocationEnd; ++i) - m_vertexIdxToBufferIdx[i] = static_cast(-2); + m_vertexIdxToBufferIdx[i] = -2; if (reservedRendererByte1) reservedRendererDword1 = allocationEnd; @@ -287,8 +295,8 @@ void Renderer::CBuffDeferredModeEnd() if (existingIndex >= 0) DeleteInternalBuffer(existingIndex); - if (static_cast(m_currentCommandBuffer + m_numBuffersToDeallocate + 10) > MAX_COMMAND_BUFFERS) - DebugBreak(); + if (static_cast(m_currentCommandBuffer + m_numBuffersToDeallocate + 10) > static_cast(m_commandBuffers.size())) + GrowCommandBufferArrays(); const int internalSlot = m_currentCommandBuffer; ++m_currentCommandBuffer; @@ -321,7 +329,7 @@ void Renderer::CBuffDelete(int first, int count) if (internalIndex >= 0) DeleteInternalBuffer(internalIndex); - m_vertexIdxToBufferIdx[i] = static_cast(-1); + m_vertexIdxToBufferIdx[i] = CBUFF_SLOT_FREE; // -1, слот полностью освобождён } LeaveCriticalSection(&m_commandBufferCS); @@ -352,8 +360,8 @@ void Renderer::CBuffEnd() if (existingIndex >= 0) DeleteInternalBuffer(existingIndex); - if (static_cast(m_currentCommandBuffer + m_numBuffersToDeallocate + 10) > MAX_COMMAND_BUFFERS) - DebugBreak(); + if (static_cast(m_currentCommandBuffer + m_numBuffersToDeallocate + 10) > static_cast(m_commandBuffers.size())) + GrowCommandBufferArrays(); const int internalSlot = m_currentCommandBuffer; ++m_currentCommandBuffer; @@ -410,27 +418,22 @@ void Renderer::CBuffTick() { EnterCriticalSection(&m_commandBufferCS); - int completedDeletes = 0; if (m_numBuffersToDeallocate > 0) { - int deleteIdx = MAX_COMMAND_BUFFERS - 1; - do - { - Renderer::CommandBuffer *buffer = m_commandBuffers[deleteIdx]; - if (buffer) - delete buffer; - m_commandBuffers[deleteIdx] = NULL; + // Удаляем ровно один буфер за тик — чтобы не спайкать кадр + const int totalSlots = static_cast(m_commandBuffers.size()); + const int deleteIdx = totalSlots - static_cast(m_numBuffersToDeallocate); - if (--m_numBuffersToDeallocate == 0) - { - ++completedDeletes; - --deleteIdx; - } - else - { - m_commandBuffers[deleteIdx] = m_commandBuffers[(MAX_COMMAND_BUFFERS - 1) - static_cast(m_numBuffersToDeallocate)]; - } - } while (completedDeletes < static_cast(m_numBuffersToDeallocate)); + CommandBuffer* buf = m_commandBuffers[deleteIdx]; + if (buf) + delete buf; + + m_commandBuffers[deleteIdx] = nullptr; + m_bufferIdxToVertexIdx[deleteIdx] = 0; + m_commandPrimitiveTypes[deleteIdx] = 0; + m_commandVertexTypes[deleteIdx] = 0; + + --m_numBuffersToDeallocate; } LeaveCriticalSection(&m_commandBufferCS); @@ -438,29 +441,49 @@ void Renderer::CBuffTick() void Renderer::DeleteInternalBuffer(int index) { - EnterCriticalSection(&m_commandBufferCS); + // Уже под m_commandBufferCS ++m_numBuffersToDeallocate; - const int index_delete = MAX_COMMAND_BUFFERS - static_cast(m_numBuffersToDeallocate); + const int totalSlots = static_cast(m_commandBuffers.size()); + const int index_delete = totalSlots - static_cast(m_numBuffersToDeallocate); + // Перемещаем удаляемый буфер в зону ожидания m_commandBuffers[index_delete] = m_commandBuffers[index]; m_commandMatrices[index_delete] = m_commandMatrices[index]; + m_bufferIdxToVertexIdx[index_delete] = m_bufferIdxToVertexIdx[index]; + m_commandPrimitiveTypes[index_delete] = m_commandPrimitiveTypes[index]; + m_commandVertexTypes[index_delete] = m_commandVertexTypes[index]; if (m_currentCommandBuffer-- != 1) { - const int mappedFrom = m_currentCommandBuffer; + const int mappedFrom = m_currentCommandBuffer; // после декремента + // Заполняем дырку последним активным буфером m_commandBuffers[index] = m_commandBuffers[mappedFrom]; m_commandMatrices[index] = m_commandMatrices[mappedFrom]; m_commandVertexTypes[index] = m_commandVertexTypes[mappedFrom]; m_commandPrimitiveTypes[index] = m_commandPrimitiveTypes[mappedFrom]; + m_bufferIdxToVertexIdx[index] = m_bufferIdxToVertexIdx[mappedFrom]; - const int commandIndex = m_bufferIdxToVertexIdx[mappedFrom]; - m_vertexIdxToBufferIdx[commandIndex] = static_cast(index); + // ВАЖНО: обнуляем старую позицию после свапа + // Без этого GrowCommandBufferArrays скопирует стейл-указатель в новый хвост + m_commandBuffers[mappedFrom] = nullptr; + m_bufferIdxToVertexIdx[mappedFrom] = 0; + m_commandPrimitiveTypes[mappedFrom] = 0; + m_commandVertexTypes[mappedFrom] = 0; + + const int commandIndex = m_bufferIdxToVertexIdx[index]; + m_vertexIdxToBufferIdx[commandIndex] = index; m_bufferIdxToVertexIdx[index] = commandIndex; } - - LeaveCriticalSection(&m_commandBufferCS); + else + { + // Последний активный буфер был удалён — обнуляем слот + m_commandBuffers[index] = nullptr; + m_bufferIdxToVertexIdx[index] = 0; + m_commandPrimitiveTypes[index] = 0; + m_commandVertexTypes[index] = 0; + } } void Renderer::CommandBuffer::EndRecording(ID3D11Device *device) diff --git a/Minecraft.Client/Windows64/4JLibs/inc/Render/RendererCore.cpp b/Minecraft.Client/Windows64/4JLibs/inc/Render/RendererCore.cpp index 0cbf944bb..3f4d39f10 100644 --- a/Minecraft.Client/Windows64/4JLibs/inc/Render/RendererCore.cpp +++ b/Minecraft.Client/Windows64/4JLibs/inc/Render/RendererCore.cpp @@ -680,18 +680,15 @@ void Renderer::Initialise(ID3D11Device *pDevice, IDXGISwapChain *pSwapChain) PROFILER_INIT(); - m_vertexIdxToBufferIdx = new int16_t[NUM_COMMAND_HANDLES]; - m_commandBuffers = new CommandBuffer *[MAX_COMMAND_BUFFERS]; - m_commandMatrices = new DirectX::XMMATRIX[MAX_COMMAND_BUFFERS]; - m_bufferIdxToVertexIdx = new int[MAX_COMMAND_BUFFERS]; - m_commandPrimitiveTypes = new uint8_t[MAX_COMMAND_BUFFERS]; - m_commandVertexTypes = new uint8_t[MAX_COMMAND_BUFFERS]; + static const int kInitialHandles = 0x800000; + static const int kInitialBuffers = 4096; - std::memset(m_vertexIdxToBufferIdx, 0xFF, NUM_COMMAND_HANDLES * sizeof(int16_t)); - std::memset(m_commandBuffers, 0, MAX_COMMAND_BUFFERS * sizeof(CommandBuffer *)); - std::memset(m_bufferIdxToVertexIdx, 0, MAX_COMMAND_BUFFERS * sizeof(int)); - std::memset(m_commandPrimitiveTypes, 0, MAX_COMMAND_BUFFERS * sizeof(uint8_t)); - std::memset(m_commandVertexTypes, 0, MAX_COMMAND_BUFFERS * sizeof(uint8_t)); + m_vertexIdxToBufferIdx.assign(kInitialHandles, -1); + m_commandBuffers.assign(kInitialBuffers, nullptr); + m_commandMatrices.resize(kInitialBuffers); + m_bufferIdxToVertexIdx.assign(kInitialBuffers, 0); + m_commandPrimitiveTypes.assign(kInitialBuffers, 0); + m_commandVertexTypes.assign(kInitialBuffers, 0); m_numBuffersToDeallocate = 0; m_bShouldScreenGrabNextFrame = false; @@ -1047,3 +1044,34 @@ Renderer::Context &Renderer::getContext() return *reinterpret_cast(TlsGetValue(Renderer::tlsIdx)); } +void Renderer::GrowCommandBufferArrays() +{ + const size_t oldSize = m_commandBuffers.size(); + const size_t newSize = oldSize * 2; + + m_commandBuffers.resize(newSize, nullptr); + m_commandMatrices.resize(newSize); + m_bufferIdxToVertexIdx.resize(newSize, 0); + m_commandPrimitiveTypes.resize(newSize, 0); + m_commandVertexTypes.resize(newSize, 0); + + if (m_numBuffersToDeallocate > 0) + { + for (DWORD i = 0; i < m_numBuffersToDeallocate; ++i) + { + const int oldIdx = static_cast(oldSize) - static_cast(m_numBuffersToDeallocate) + static_cast(i); + const int newIdx = static_cast(newSize) - static_cast(m_numBuffersToDeallocate) + static_cast(i); + + m_commandBuffers[newIdx] = m_commandBuffers[oldIdx]; + m_commandMatrices[newIdx] = m_commandMatrices[oldIdx]; + m_bufferIdxToVertexIdx[newIdx] = m_bufferIdxToVertexIdx[oldIdx]; + m_commandPrimitiveTypes[newIdx] = m_commandPrimitiveTypes[oldIdx]; + m_commandVertexTypes[newIdx] = m_commandVertexTypes[oldIdx]; + + m_commandBuffers[oldIdx] = nullptr; + m_bufferIdxToVertexIdx[oldIdx] = 0; + m_commandPrimitiveTypes[oldIdx] = 0; + m_commandVertexTypes[oldIdx] = 0; + } + } +} diff --git a/Minecraft.Client/Windows64/4JLibs/libs/4J_Render_PC.lib b/Minecraft.Client/Windows64/4JLibs/libs/4J_Render_PC.lib index e9f4995cf..3b9b61dc6 100644 Binary files a/Minecraft.Client/Windows64/4JLibs/libs/4J_Render_PC.lib and b/Minecraft.Client/Windows64/4JLibs/libs/4J_Render_PC.lib differ diff --git a/Minecraft.World/ChunkSource.h b/Minecraft.World/ChunkSource.h index 7b5754937..664d3be47 100644 --- a/Minecraft.World/ChunkSource.h +++ b/Minecraft.World/ChunkSource.h @@ -7,12 +7,12 @@ class TilePos; // The maximum number of chunks that we can store #ifdef _LARGE_WORLDS // 4J Stu - Our default map (at zoom level 3) is 1024x1024 blocks (or 64 chunks) -#define LEVEL_MAX_WIDTH (7*64) //(6*54) +#define LEVEL_MAX_WIDTH (64*64) //(6*54) #define LEVEL_WIDTH_CLASSIC 64 #define LEVEL_WIDTH_SMALL 256 #define LEVEL_WIDTH_MEDIUM (5*64) -#define LEVEL_WIDTH_LARGE (7*64) +#define LEVEL_WIDTH_LARGE LEVEL_MAX_WIDTH #else #define LEVEL_MAX_WIDTH 54 diff --git a/Minecraft.World/Layer.cpp b/Minecraft.World/Layer.cpp index a0eda52f7..1f71f0e0b 100644 --- a/Minecraft.World/Layer.cpp +++ b/Minecraft.World/Layer.cpp @@ -31,7 +31,7 @@ LayerArray Layer::getDefaultLayers(int64_t seed, LevelType *levelType) islandLayer = std::make_shared(3, islandLayer); islandLayer = std::make_shared(2003, islandLayer); islandLayer = std::make_shared(4, islandLayer); -// islandLayer = shared_ptr(new AddMushroomIslandLayer(5, islandLayer)); // 4J - old position of mushroom island layer + islandLayer = shared_ptr(new AddMushroomIslandLayer(5, islandLayer)); // 4J - old position of mushroom island layer int zoomLevel = 4; if (levelType == LevelType::lvl_largeBiomes) @@ -39,7 +39,7 @@ LayerArray Layer::getDefaultLayers(int64_t seed, LevelType *levelType) zoomLevel = 6; } - shared_ptr riverLayer = islandLayer; + shared_ptr riverLayer = std::make_shared(100, islandLayer); riverLayer = ZoomLayer::zoom(1000, riverLayer, 0); riverLayer = std::make_shared(100, riverLayer); riverLayer = ZoomLayer::zoom(1000, riverLayer, zoomLevel + 2); @@ -64,7 +64,7 @@ LayerArray Layer::getDefaultLayers(int64_t seed, LevelType *levelType) // 4J - moved mushroom islands to here. This skips 3 zooms that the old location of the add was, making them about 1/8 of the original size. Adding // them at this scale actually lets us place them near enough other land, if we add them at the same scale as java then they have to be too far out to see for // the scale of our maps - biomeLayer = std::make_shared(5, biomeLayer); + biomeLayer = std::make_shared(10, biomeLayer); } if (i == 1 ) @@ -72,7 +72,7 @@ LayerArray Layer::getDefaultLayers(int64_t seed, LevelType *levelType) // 4J - now expand mushroom islands up again. This does a simple region grow to add a new mushroom island element when any of the neighbours are also mushroom islands. // This helps make the islands into nice compact shapes of the type that are actually likely to be able to make an island out of the sea in a small space. Also // helps the shore layer from doing too much damage in shrinking the islands we are making - biomeLayer = std::make_shared(5, biomeLayer); + biomeLayer = std::make_shared(10, biomeLayer); // Note - this reduces the size of mushroom islands by turning their edges into shores. We are doing this at i == 1 rather than i == 0 as the original does biomeLayer = std::make_shared(1000, biomeLayer); @@ -95,7 +95,7 @@ LayerArray Layer::getDefaultLayers(int64_t seed, LevelType *levelType) shared_ptr debugLayer = biomeLayer; - shared_ptrzoomedLayer = std::make_shared(10, biomeLayer); + shared_ptrzoomedLayer = std::make_shared(20, biomeLayer); biomeLayer->init(seed); zoomedLayer->init(seed); @@ -113,11 +113,11 @@ Layer::Layer(int64_t seedMixup) this->seedMixup = seedMixup; this->seedMixup *= this->seedMixup * 6364136223846793005l + 1442695040888963407l; - this->seedMixup += seedMixup; + this->seedMixup += seedMixup + 1; this->seedMixup *= this->seedMixup * 6364136223846793005l + 1442695040888963407l; - this->seedMixup += seedMixup; + this->seedMixup += seedMixup + 2; this->seedMixup *= this->seedMixup * 6364136223846793005l + 1442695040888963407l; - this->seedMixup += seedMixup; + this->seedMixup += seedMixup + 3; } void Layer::init(int64_t seed) @@ -125,11 +125,11 @@ void Layer::init(int64_t seed) this->seed = seed; if (parent != nullptr) parent->init(seed); this->seed *= this->seed * 6364136223846793005l + 1442695040888963407l; - this->seed += seedMixup; + this->seed += seedMixup + 1; this->seed *= this->seed * 6364136223846793005l + 1442695040888963407l; - this->seed += seedMixup; + this->seed += seedMixup + 2; this->seed *= this->seed * 6364136223846793005l + 1442695040888963407l; - this->seed += seedMixup; + this->seed += seedMixup + 3; } void Layer::initRandom(int64_t x, int64_t y) diff --git a/MinecraftConsoles.sln b/MinecraftConsoles.sln index 5ef01ae23..8f73c57e7 100644 --- a/MinecraftConsoles.sln +++ b/MinecraftConsoles.sln @@ -7,6 +7,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Minecraft.World", "Minecraf EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Minecraft.Client", "Minecraft.Client\Minecraft.Client.vcxproj", "{1B9A8C38-DD48-448C-AA24-E1A35E0089A3}" ProjectSection(ProjectDependencies) = postProject + {CC99EB47-7231-4067-8717-C6BF4ABDE338} = {CC99EB47-7231-4067-8717-C6BF4ABDE338} {F046C3CE-9749-4823-B32B-D9CC10B1A2C8} = {F046C3CE-9749-4823-B32B-D9CC10B1A2C8} EndProjectSection EndProject