Multidraw
This commit is contained in:
parent
f08afbf654
commit
d4c0f54245
2
dependencies/gles-compatibility-layer/src
vendored
2
dependencies/gles-compatibility-layer/src
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 68561e0404a4ad09e523129bca67cf6be8cec2fc
|
Subproject commit fedc5ac21865fe44dcbc7adb0818af612205cd57
|
@ -69,3 +69,4 @@ TRUE Add Reborn Info To Options
|
|||||||
FALSE Log FPS
|
FALSE Log FPS
|
||||||
TRUE Add Welcome Screen
|
TRUE Add Welcome Screen
|
||||||
TRUE F3 Debug Information
|
TRUE F3 Debug Information
|
||||||
|
TRUE Multidraw Rendering
|
@ -565,3 +565,12 @@ void media_get_framebuffer_size(int *width, int *height) {
|
|||||||
*height = DEFAULT_HEIGHT;
|
*height = DEFAULT_HEIGHT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check OpenGL Extension
|
||||||
|
int media_has_extension(const char *name) {
|
||||||
|
if (glfw_window) {
|
||||||
|
return glfwExtensionSupported(name);
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
@ -22,6 +22,7 @@ void media_set_interactable(int is_interactable);
|
|||||||
void media_disable_vsync();
|
void media_disable_vsync();
|
||||||
void media_force_egl();
|
void media_force_egl();
|
||||||
void media_set_raw_mouse_motion_enabled(int enabled);
|
void media_set_raw_mouse_motion_enabled(int enabled);
|
||||||
|
int media_has_extension(const char *name);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
@ -138,6 +138,23 @@ CALL(15, glDrawArrays, void, (GLenum mode, GLint first, GLsizei count))
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef MCPI_USE_GLES1_COMPATIBILITY_LAYER
|
||||||
|
CALL(70, glMultiDrawArrays, void, (GLenum mode, const GLint *first, const GLsizei *count, GLsizei drawcount))
|
||||||
|
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||||
|
trampoline(true, gl_state, mode, copy_array(drawcount, first), copy_array(drawcount, count));
|
||||||
|
#else
|
||||||
|
gl_state_t gl_state = args.next<gl_state_t>();
|
||||||
|
gl_state.send_to_driver();
|
||||||
|
GLenum mode = args.next<GLenum>();
|
||||||
|
uint32_t drawcount;
|
||||||
|
const GLint *first = args.next_arr<GLint>(&drawcount);
|
||||||
|
const GLsizei *count = args.next_arr<GLsizei>();
|
||||||
|
func(mode, first, count, GLsizei(drawcount));
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
CALL(16, glColor4f, void, (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha))
|
CALL(16, glColor4f, void, (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha))
|
||||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||||
trampoline(true, red, green, blue, alpha);
|
trampoline(true, red, green, blue, alpha);
|
||||||
@ -162,14 +179,14 @@ CALL(17, glClear, void, (GLbitfield mask))
|
|||||||
|
|
||||||
CALL(18, glBufferData, void, (GLenum target, GLsizeiptr size, const void *data, GLenum usage))
|
CALL(18, glBufferData, void, (GLenum target, GLsizeiptr size, const void *data, GLenum usage))
|
||||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||||
trampoline(true, gl_state.bound_array_buffer, target, copy_array(size, (unsigned char *) data), usage);
|
trampoline(true, gl_state.bound_array_buffer, target, int32_t(size), copy_array(size, (unsigned char *) data), usage);
|
||||||
#else
|
#else
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, args.next<GLuint>());
|
glBindBuffer(GL_ARRAY_BUFFER, args.next<GLuint>());
|
||||||
GLenum target = args.next<GLenum>();
|
GLenum target = args.next<GLenum>();
|
||||||
uint32_t size;
|
int32_t size = args.next<int32_t>();
|
||||||
const unsigned char *data = args.next_arr<unsigned char>(&size);
|
const unsigned char *data = args.next_arr<unsigned char>();
|
||||||
GLenum usage = args.next<GLenum>();
|
GLenum usage = args.next<GLenum>();
|
||||||
func(target, GLsizeiptr(size), data, usage);
|
func(target, size, data, usage);
|
||||||
return 0;
|
return 0;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -738,3 +755,17 @@ CALL(67, glGenBuffers, void, (GLsizei n, GLuint *buffers))
|
|||||||
return 0;
|
return 0;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CALL(69, glBufferSubData, void, (GLenum target, GLintptr offset, GLsizeiptr size, const void *data))
|
||||||
|
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||||
|
trampoline(true, gl_state.bound_array_buffer, target, int32_t(offset), int32_t(size), copy_array(size, (unsigned char *) data));
|
||||||
|
#else
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, args.next<GLuint>());
|
||||||
|
GLenum target = args.next<GLenum>();
|
||||||
|
int32_t offset = args.next<int32_t>();
|
||||||
|
int32_t size = args.next<int32_t>();
|
||||||
|
const unsigned char *data = args.next_arr<unsigned char>();
|
||||||
|
func(target, offset, size, data);
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
@ -38,6 +38,9 @@ struct TrampolineArguments {
|
|||||||
if (length != nullptr) {
|
if (length != nullptr) {
|
||||||
*length = size / sizeof(T);
|
*length = size / sizeof(T);
|
||||||
}
|
}
|
||||||
|
if (size == 0) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
const T *ret = (const T *) raw_args;
|
const T *ret = (const T *) raw_args;
|
||||||
raw_args += size;
|
raw_args += size;
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -182,3 +182,11 @@ CALL(68, media_ensure_loaded, void, ())
|
|||||||
return 0;
|
return 0;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CALL(71, media_has_extension, int, (const char *name))
|
||||||
|
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||||
|
return trampoline(false, copy_array(name));
|
||||||
|
#else
|
||||||
|
return func(args.next_arr<char>());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
@ -89,6 +89,10 @@ set(SRC
|
|||||||
src/init/init.cpp
|
src/init/init.cpp
|
||||||
# f3
|
# f3
|
||||||
src/f3/f3.cpp
|
src/f3/f3.cpp
|
||||||
|
# multidraw
|
||||||
|
src/multidraw/glue.cpp
|
||||||
|
src/multidraw/buffer.cpp
|
||||||
|
src/multidraw/storage.cpp
|
||||||
)
|
)
|
||||||
# Install Splashes
|
# Install Splashes
|
||||||
install(
|
install(
|
||||||
|
@ -29,4 +29,5 @@ void init_home();
|
|||||||
void init_override();
|
void init_override();
|
||||||
void init_screenshot();
|
void init_screenshot();
|
||||||
void init_f3();
|
void init_f3();
|
||||||
|
void init_multidraw();
|
||||||
}
|
}
|
||||||
|
@ -43,5 +43,6 @@ __attribute__((constructor)) static void init() {
|
|||||||
if (!reborn_is_headless()) {
|
if (!reborn_is_headless()) {
|
||||||
init_screenshot();
|
init_screenshot();
|
||||||
init_f3();
|
init_f3();
|
||||||
|
init_multidraw();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -724,7 +724,7 @@ static void sort_chunks(Chunk **chunks_begin, Chunk **chunks_end, DistanceChunkS
|
|||||||
// Display Date In Select World Screen
|
// Display Date In Select World Screen
|
||||||
static std::string AppPlatform_linux_getDateString_injection(__attribute__((unused)) AppPlatform_linux *app_platform, int time) {
|
static std::string AppPlatform_linux_getDateString_injection(__attribute__((unused)) AppPlatform_linux *app_platform, int time) {
|
||||||
// From https://github.com/ReMinecraftPE/mcpe/blob/56e51027b1c2e67fe5a0e8a091cefe51d4d11926/platforms/sdl/base/AppPlatform_sdl_base.cpp#L68-L84
|
// From https://github.com/ReMinecraftPE/mcpe/blob/56e51027b1c2e67fe5a0e8a091cefe51d4d11926/platforms/sdl/base/AppPlatform_sdl_base.cpp#L68-L84
|
||||||
time_t tt = time;
|
const time_t tt = time;
|
||||||
tm t = {};
|
tm t = {};
|
||||||
gmtime_r(&tt, &t);
|
gmtime_r(&tt, &t);
|
||||||
char buf[2048];
|
char buf[2048];
|
||||||
|
29
mods/src/multidraw/buffer.cpp
Normal file
29
mods/src/multidraw/buffer.cpp
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
#include "buffer.h"
|
||||||
|
|
||||||
|
// Setup Buffer
|
||||||
|
Buffer::Buffer(const ssize_t size) {
|
||||||
|
// Client-Side Data
|
||||||
|
client_side_data = new unsigned char[size];
|
||||||
|
// Server-Side Data
|
||||||
|
server_side_data = 0;
|
||||||
|
glGenBuffers(1, &server_side_data);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, server_side_data);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, size, nullptr, GL_DYNAMIC_DRAW);
|
||||||
|
}
|
||||||
|
Buffer::~Buffer() {
|
||||||
|
// Client-Side Data
|
||||||
|
delete[] client_side_data;
|
||||||
|
// Server-Side Data
|
||||||
|
glDeleteBuffers(1, &server_side_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Upload Data
|
||||||
|
void Buffer::upload(const intptr_t offset, const ssize_t size, const void *data) const {
|
||||||
|
// Client-Side Data
|
||||||
|
memcpy(client_side_data + offset, data, size);
|
||||||
|
// Server-Side Data
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, server_side_data);
|
||||||
|
glBufferSubData(GL_ARRAY_BUFFER, offset, size, data);
|
||||||
|
}
|
21
mods/src/multidraw/buffer.h
Normal file
21
mods/src/multidraw/buffer.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <GLES/gl.h>
|
||||||
|
|
||||||
|
// Keep An OpenGL Buffer And Client-Side Memory Synchronized
|
||||||
|
struct Buffer {
|
||||||
|
explicit Buffer(ssize_t size);
|
||||||
|
~Buffer();
|
||||||
|
|
||||||
|
// Prevent Copying
|
||||||
|
Buffer(const Buffer &) = delete;
|
||||||
|
Buffer &operator=(const Buffer &) = delete;
|
||||||
|
|
||||||
|
// Data
|
||||||
|
GLuint server_side_data;
|
||||||
|
unsigned char *client_side_data;
|
||||||
|
|
||||||
|
// Upload Data
|
||||||
|
void upload(intptr_t offset, ssize_t size, const void *data) const;
|
||||||
|
};
|
135
mods/src/multidraw/glue.cpp
Normal file
135
mods/src/multidraw/glue.cpp
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
#include <GLES/gl.h>
|
||||||
|
|
||||||
|
#include <symbols/minecraft.h>
|
||||||
|
#include <libreborn/libreborn.h>
|
||||||
|
#include <media-layer/core.h>
|
||||||
|
|
||||||
|
#include <mods/init/init.h>
|
||||||
|
#include <mods/feature/feature.h>
|
||||||
|
|
||||||
|
#include "storage.h"
|
||||||
|
|
||||||
|
// Fake Buffer IDs To Correspond To The Multidraw Storage
|
||||||
|
#define MULTIDRAW_BASE 1073741823
|
||||||
|
|
||||||
|
// Setup
|
||||||
|
static Storage *storage = nullptr;
|
||||||
|
static void setup_multidraw(int chunks, GLuint *buffers) {
|
||||||
|
delete storage;
|
||||||
|
storage = new Storage(chunks);
|
||||||
|
for (int i = 0; i < chunks; i++) {
|
||||||
|
buffers[i] = i + MULTIDRAW_BASE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
HOOK(glDeleteBuffers, void, (GLsizei n, const GLuint *buffers)) {
|
||||||
|
if (buffers[0] >= MULTIDRAW_BASE) {
|
||||||
|
delete storage;
|
||||||
|
} else {
|
||||||
|
ensure_glDeleteBuffers();
|
||||||
|
real_glDeleteBuffers(n, buffers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Usage
|
||||||
|
static int current_chunk = -1;
|
||||||
|
HOOK(glBindBuffer, void, (const GLenum target, GLuint buffer)) {
|
||||||
|
if (target == GL_ARRAY_BUFFER && buffer >= MULTIDRAW_BASE && storage != nullptr) {
|
||||||
|
current_chunk = int(buffer - MULTIDRAW_BASE);
|
||||||
|
buffer = storage->buffer->server_side_data;
|
||||||
|
} else {
|
||||||
|
current_chunk = -1;
|
||||||
|
}
|
||||||
|
ensure_glBindBuffer();
|
||||||
|
real_glBindBuffer(target, buffer);
|
||||||
|
}
|
||||||
|
HOOK(glBufferData, void, (GLenum target, GLsizeiptr size, const void *data, GLenum usage)) {
|
||||||
|
if (target == GL_ARRAY_BUFFER && current_chunk >= 0 && storage != nullptr) {
|
||||||
|
storage->upload(current_chunk, size, data);
|
||||||
|
} else {
|
||||||
|
ensure_glBufferData();
|
||||||
|
real_glBufferData(target, size, data, usage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#define VERTEX_SIZE 24
|
||||||
|
#define MAX_RENDER_CHUNKS 4096
|
||||||
|
static bool supports_multidraw() {
|
||||||
|
static int ret = -1;
|
||||||
|
if (ret == -1) {
|
||||||
|
ret = media_has_extension("GL_EXT_multi_draw_arrays");
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
static int LevelRenderer_renderChunks_injection(__attribute__((unused)) LevelRenderer_renderChunks_t original, LevelRenderer *self, const int start, const int end, const int a, const float b) {
|
||||||
|
// Prepare Offset
|
||||||
|
self->render_list.clear();
|
||||||
|
const Mob *camera = self->minecraft->camera;
|
||||||
|
const float x = camera->old_x + ((camera->x - camera->old_x) * b);
|
||||||
|
const float y = camera->old_y + ((camera->y - camera->old_y) * b);
|
||||||
|
const float z = camera->old_z + ((camera->z - camera->old_z) * b);
|
||||||
|
glPushMatrix();
|
||||||
|
glTranslatef(-x, -y, -z);
|
||||||
|
|
||||||
|
// Setup OpenGL
|
||||||
|
glEnableClientState(GL_VERTEX_ARRAY);
|
||||||
|
glEnableClientState(GL_COLOR_ARRAY);
|
||||||
|
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, storage->buffer->server_side_data);
|
||||||
|
glVertexPointer(3, GL_FLOAT, VERTEX_SIZE, (void *) 0);
|
||||||
|
glTexCoordPointer(2, GL_FLOAT, VERTEX_SIZE, (void *) 0xc);
|
||||||
|
glColorPointer(4, GL_UNSIGNED_BYTE, VERTEX_SIZE, (void *) 0x14);
|
||||||
|
|
||||||
|
// Batch
|
||||||
|
static GLint firsts[MAX_RENDER_CHUNKS];
|
||||||
|
static GLsizei counts[MAX_RENDER_CHUNKS];
|
||||||
|
GLsizei total = 0;
|
||||||
|
for (int i = start; i < end; i++) {
|
||||||
|
Chunk *chunk = self->chunks[i];
|
||||||
|
// Check If Chunk Is Visible
|
||||||
|
if (!chunk->field_1c[a] && chunk->visible) {
|
||||||
|
const RenderChunk *render_chunk = chunk->getRenderChunk(a);
|
||||||
|
// Get Data Block
|
||||||
|
const int chunk_id = int(render_chunk->buffer - MULTIDRAW_BASE);
|
||||||
|
const Block *block = storage->chunk_to_block[chunk_id];
|
||||||
|
if (block == nullptr) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Queue
|
||||||
|
const int j = total++;
|
||||||
|
firsts[j] = block->offset / VERTEX_SIZE;
|
||||||
|
counts[j] = render_chunk->vertices;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw
|
||||||
|
#ifdef MCPI_USE_GLES1_COMPATIBILITY_LAYER
|
||||||
|
if (supports_multidraw()) {
|
||||||
|
glMultiDrawArrays(GL_TRIANGLES, firsts, counts, total);
|
||||||
|
} else {
|
||||||
|
#endif
|
||||||
|
for (int i = 0; i < total; i++) {
|
||||||
|
glDrawArrays(GL_TRIANGLES, firsts[i], counts[i]);
|
||||||
|
}
|
||||||
|
#ifdef MCPI_USE_GLES1_COMPATIBILITY_LAYER
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
glDisableClientState(GL_COLOR_ARRAY);
|
||||||
|
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||||
|
glPopMatrix();
|
||||||
|
|
||||||
|
// Return
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init
|
||||||
|
void init_multidraw() {
|
||||||
|
// Setup
|
||||||
|
if (feature_has("Multidraw Rendering", server_disabled)) {
|
||||||
|
overwrite_call((void *) 0x4e51c, (void *) setup_multidraw);
|
||||||
|
overwrite_call((void *) 0x4e6f8, (void *) setup_multidraw);
|
||||||
|
overwrite_calls(LevelRenderer_renderChunks, LevelRenderer_renderChunks_injection);
|
||||||
|
unsigned char nop_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; // "nop"
|
||||||
|
patch((void *) 0x479fc, nop_patch);
|
||||||
|
}
|
||||||
|
}
|
185
mods/src/multidraw/storage.cpp
Normal file
185
mods/src/multidraw/storage.cpp
Normal file
@ -0,0 +1,185 @@
|
|||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include "storage.h"
|
||||||
|
|
||||||
|
#include <libreborn/libreborn.h>
|
||||||
|
|
||||||
|
// Setup
|
||||||
|
#define DEFAULT_SIZE 16777216 // 16 MiB
|
||||||
|
Storage::Storage(const int chunks) {
|
||||||
|
// Allocate
|
||||||
|
total_size = DEFAULT_SIZE;
|
||||||
|
used_size = 0;
|
||||||
|
for (int i = 0; i < chunks; i++) {
|
||||||
|
chunk_to_block.push_back(nullptr);
|
||||||
|
}
|
||||||
|
buffer = new Buffer(total_size);
|
||||||
|
// First Free Block
|
||||||
|
Block *block = new Block;
|
||||||
|
block->offset = 0;
|
||||||
|
block->size = total_size;
|
||||||
|
free_blocks.push_back(block);
|
||||||
|
}
|
||||||
|
Storage::~Storage() {
|
||||||
|
delete buffer;
|
||||||
|
for (const std::vector<Block *> &blocks : {free_blocks, used_blocks}) {
|
||||||
|
for (const Block *block : blocks) {
|
||||||
|
delete block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Free Block
|
||||||
|
void Storage::free_block(Block *block) {
|
||||||
|
// Check
|
||||||
|
if (block == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find Block
|
||||||
|
std::vector<Block *>::iterator it = std::find(used_blocks.begin(), used_blocks.end(), block);
|
||||||
|
if (it == used_blocks.end()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
used_blocks.erase(it);
|
||||||
|
|
||||||
|
// Update Size
|
||||||
|
used_size -= block->size;
|
||||||
|
|
||||||
|
// Merge With Next/Previous Blocks
|
||||||
|
for (it = free_blocks.begin(); it < free_blocks.end(); ++it) {
|
||||||
|
const Block *x = *it;
|
||||||
|
if (x->offset == (block->offset + block->size)) {
|
||||||
|
// Found Free Block After Target
|
||||||
|
block->size += x->size;
|
||||||
|
free_blocks.erase(it);
|
||||||
|
delete x;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (it = free_blocks.begin(); it < free_blocks.end(); ++it) {
|
||||||
|
const Block *x = *it;
|
||||||
|
if ((x->offset + x->size) == block->offset) {
|
||||||
|
// Found Free Block Before Target
|
||||||
|
block->size += x->size;
|
||||||
|
block->offset -= x->size;
|
||||||
|
free_blocks.erase(it);
|
||||||
|
delete x;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add To Free Block List
|
||||||
|
free_blocks.push_back(block);
|
||||||
|
|
||||||
|
// Fragmentation
|
||||||
|
check_fragmentation();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check Fragmentation
|
||||||
|
ssize_t Storage::get_end() const {
|
||||||
|
ssize_t end = 0;
|
||||||
|
for (const Block *block : used_blocks) {
|
||||||
|
const ssize_t new_end = block->offset + block->size;
|
||||||
|
if (new_end > end) {
|
||||||
|
end = new_end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return end;
|
||||||
|
}
|
||||||
|
void Storage::check_fragmentation() {
|
||||||
|
const ssize_t end = get_end();
|
||||||
|
if (end == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const float fragmentation = 1.0f - (float(used_size) / float(end));
|
||||||
|
if (fragmentation >= 0.5f) {
|
||||||
|
// 50% Fragmentation
|
||||||
|
recreate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Upload Chunk
|
||||||
|
void Storage::upload(const int chunk, const ssize_t size, const void *data) {
|
||||||
|
// Free Old Block
|
||||||
|
free_block(chunk_to_block[chunk]);
|
||||||
|
|
||||||
|
// Check Size
|
||||||
|
if (size == 0) {
|
||||||
|
chunk_to_block[chunk] = nullptr;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find Free Block
|
||||||
|
std::vector<Block *>::iterator it;
|
||||||
|
while (true) {
|
||||||
|
for (it = free_blocks.begin(); it < free_blocks.end(); ++it) {
|
||||||
|
if ((*it)->size >= size) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (it == free_blocks.end()) {
|
||||||
|
// Get Extra Space
|
||||||
|
recreate(size);
|
||||||
|
} else {
|
||||||
|
// Done!
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Block *old_free_block = *it;
|
||||||
|
|
||||||
|
// Create New Used Block
|
||||||
|
Block *new_used_block = new Block;
|
||||||
|
new_used_block->offset = old_free_block->offset;
|
||||||
|
new_used_block->size = size;
|
||||||
|
used_blocks.push_back(new_used_block);
|
||||||
|
// Update Old Free Block
|
||||||
|
old_free_block->offset += size;
|
||||||
|
old_free_block->size -= size;
|
||||||
|
if (old_free_block->size == 0) {
|
||||||
|
free_blocks.erase(it);
|
||||||
|
delete old_free_block;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Upload
|
||||||
|
buffer->upload(new_used_block->offset, size, data);
|
||||||
|
|
||||||
|
// Assign Block To Chunk
|
||||||
|
chunk_to_block[chunk] = new_used_block;
|
||||||
|
|
||||||
|
// Update Size
|
||||||
|
used_size += size;
|
||||||
|
|
||||||
|
// Check Fragmentation
|
||||||
|
check_fragmentation();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recreate/Defragment
|
||||||
|
void Storage::recreate(const ssize_t extra_size) {
|
||||||
|
// Create New Buffer
|
||||||
|
const ssize_t new_size = (used_size + extra_size) * 2;
|
||||||
|
Buffer *new_buffer = new Buffer(new_size);
|
||||||
|
|
||||||
|
// Copy Used Blocks
|
||||||
|
intptr_t offset = 0;
|
||||||
|
for (Block *block : used_blocks) {
|
||||||
|
new_buffer->upload(offset, block->size, buffer->client_side_data + block->offset);
|
||||||
|
block->offset = offset;
|
||||||
|
offset += block->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update Free Blocks
|
||||||
|
for (const Block *block : free_blocks) {
|
||||||
|
delete block;
|
||||||
|
}
|
||||||
|
free_blocks.clear();
|
||||||
|
Block *block = new Block;
|
||||||
|
block->offset = offset;
|
||||||
|
block->size = new_size - offset;
|
||||||
|
free_blocks.push_back(block);
|
||||||
|
|
||||||
|
// Use New Buffer
|
||||||
|
delete buffer;
|
||||||
|
buffer = new_buffer;
|
||||||
|
total_size = new_size;
|
||||||
|
}
|
41
mods/src/multidraw/storage.h
Normal file
41
mods/src/multidraw/storage.h
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "buffer.h"
|
||||||
|
|
||||||
|
// Block Of Data
|
||||||
|
struct Block {
|
||||||
|
intptr_t offset;
|
||||||
|
ssize_t size;
|
||||||
|
// Prevent Copying
|
||||||
|
Block() {
|
||||||
|
offset = 0;
|
||||||
|
size = 0;
|
||||||
|
}
|
||||||
|
Block(const Block &) = delete;
|
||||||
|
Block &operator=(const Block &) = delete;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Storage
|
||||||
|
struct Storage {
|
||||||
|
explicit Storage(int chunks);
|
||||||
|
~Storage();
|
||||||
|
|
||||||
|
// Buffer
|
||||||
|
Buffer *buffer;
|
||||||
|
|
||||||
|
// Chunks
|
||||||
|
std::vector<Block *> chunk_to_block;
|
||||||
|
void upload(int chunk, ssize_t size, const void *data);
|
||||||
|
|
||||||
|
// Management
|
||||||
|
ssize_t total_size;
|
||||||
|
ssize_t used_size;
|
||||||
|
std::vector<Block *> free_blocks;
|
||||||
|
std::vector<Block *> used_blocks;
|
||||||
|
void free_block(Block *block);
|
||||||
|
void recreate(ssize_t extra_size = 0);
|
||||||
|
void check_fragmentation();
|
||||||
|
ssize_t get_end() const;
|
||||||
|
};
|
@ -91,11 +91,11 @@ void screenshot_take(Gui *gui) {
|
|||||||
if (save_png(file.c_str(), pixels, line_size, width, height)) {
|
if (save_png(file.c_str(), pixels, line_size, width, height)) {
|
||||||
WARN("Screenshot Failed: %s", file.c_str());
|
WARN("Screenshot Failed: %s", file.c_str());
|
||||||
} else {
|
} else {
|
||||||
std::string msg = "Screenshot Saved: ";
|
INFO("Screenshot Saved: %s", file.c_str());
|
||||||
INFO("%s%s", msg.c_str(), file.c_str());
|
|
||||||
if (gui) {
|
if (gui) {
|
||||||
msg += filename;
|
std::string chat_msg = "Saved screenshot as ";
|
||||||
gui->addMessage(&msg);
|
chat_msg += filename;
|
||||||
|
gui->addMessage(&chat_msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,9 +79,9 @@ set(SRC
|
|||||||
src/level/ChunkStorage.def
|
src/level/ChunkStorage.def
|
||||||
src/level/LightLayer.def
|
src/level/LightLayer.def
|
||||||
src/level/Level.def
|
src/level/Level.def
|
||||||
src/level/LevelRenderer.def
|
src/level/renderer/LevelRenderer.def
|
||||||
src/level/LevelStorageSource.def
|
src/level/LevelStorageSource.def
|
||||||
src/level/ParticleEngine.def
|
src/level/renderer/ParticleEngine.def
|
||||||
src/level/RandomLevelSource.def
|
src/level/RandomLevelSource.def
|
||||||
src/level/LevelData.def
|
src/level/LevelData.def
|
||||||
src/level/LevelSettings.def
|
src/level/LevelSettings.def
|
||||||
@ -90,7 +90,7 @@ set(SRC
|
|||||||
src/level/MultiPlayerLevel.def
|
src/level/MultiPlayerLevel.def
|
||||||
src/level/LevelSummary.def
|
src/level/LevelSummary.def
|
||||||
src/level/DistanceChunkSorter.def
|
src/level/DistanceChunkSorter.def
|
||||||
src/level/Chunk.def
|
src/level/renderer/Chunk.def
|
||||||
src/item/ItemRenderer.def
|
src/item/ItemRenderer.def
|
||||||
src/item/ItemInHandRenderer.def
|
src/item/ItemInHandRenderer.def
|
||||||
src/item/AuxDataTileItem.def
|
src/item/AuxDataTileItem.def
|
||||||
@ -161,6 +161,8 @@ set(SRC
|
|||||||
src/misc/Vec3.def
|
src/misc/Vec3.def
|
||||||
src/misc/HitResult.def
|
src/misc/HitResult.def
|
||||||
src/misc/PerfRenderer.def
|
src/misc/PerfRenderer.def
|
||||||
|
src/level/renderer/RenderList.def
|
||||||
|
src/level/renderer/RenderChunk.def
|
||||||
src/textures/Texture.def
|
src/textures/Texture.def
|
||||||
src/textures/Textures.def
|
src/textures/Textures.def
|
||||||
src/textures/DynamicTexture.def
|
src/textures/DynamicTexture.def
|
||||||
|
@ -1,5 +0,0 @@
|
|||||||
property int x = 0x4;
|
|
||||||
property int y = 0x8;
|
|
||||||
property int z = 0xc;
|
|
||||||
|
|
||||||
method float distanceToSqr(Entity *entity) = 0x47ba0;
|
|
9
symbols/src/level/renderer/Chunk.def
Normal file
9
symbols/src/level/renderer/Chunk.def
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
property int x = 0x4;
|
||||||
|
property int y = 0x8;
|
||||||
|
property int z = 0xc;
|
||||||
|
property bool field_1c[3] = 0x1c;
|
||||||
|
property bool visible = 0x4c;
|
||||||
|
|
||||||
|
method float distanceToSqr(Entity *entity) = 0x47ba0;
|
||||||
|
method int getList(int a) = 0x47e48;
|
||||||
|
method RenderChunk *getRenderChunk(int a) = 0x47e74;
|
@ -4,5 +4,8 @@ method void renderDebug(AABB *aabb, float delta) = 0x4d310;
|
|||||||
method void generateSky() = 0x4d0d4;
|
method void generateSky() = 0x4d0d4;
|
||||||
method void renderHitSelect(Player *player, HitResult *hit_result, int i, void *vp, float f) = 0x4e318;
|
method void renderHitSelect(Player *player, HitResult *hit_result, int i, void *vp, float f) = 0x4e318;
|
||||||
method void renderHitOutline(Player *player, HitResult *hit_result, int i, void *vp, float f) = 0x4dc14;
|
method void renderHitOutline(Player *player, HitResult *hit_result, int i, void *vp, float f) = 0x4dc14;
|
||||||
|
method int renderChunks(int start, int end, int a, float b) = 0x4f35c;
|
||||||
|
|
||||||
property Minecraft *minecraft = 0x4;
|
property Minecraft *minecraft = 0xb4;
|
||||||
|
property RenderList render_list = 0x34;
|
||||||
|
property Chunk **chunks = 0x98;
|
7
symbols/src/level/renderer/RenderChunk.def
Normal file
7
symbols/src/level/renderer/RenderChunk.def
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
size 0x18;
|
||||||
|
|
||||||
|
property uint buffer = 0x0;
|
||||||
|
property int vertices = 0x4;
|
||||||
|
property float x = 0xc;
|
||||||
|
property float y = 0x10;
|
||||||
|
property float z = 0x14;
|
9
symbols/src/level/renderer/RenderList.def
Normal file
9
symbols/src/level/renderer/RenderList.def
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
method void render() = 0x52800;
|
||||||
|
method void renderChunks() = 0x52708;
|
||||||
|
method void clear() = 0x5288c;
|
||||||
|
method void init(float x, float y, float z) = 0x526bc;
|
||||||
|
method void addR(RenderChunk *chunk) = 0x526dc;
|
||||||
|
|
||||||
|
property int size = 0x1c;
|
||||||
|
property RenderChunk *chunks = 0x10;
|
||||||
|
property int field_14 = 0x14;
|
Loading…
Reference in New Issue
Block a user