Skip to content

Commit a26bed6

Browse files
committed
PalettedBlockArray: allow getting and providing palette as raw bytes, instead of an array
closes #36 This is significantly faster, particularly in the 16 bpb case, which shows a combined performance improvement of 24500 ns -> 1700 ns for recreating a paletted array using a string instead of an array. We really were paying a hilariously large performance penalty for processing these as an array, even just within the extension itself. Not to mention the cost of needing to use pack() and unpack() in "Fast"ChunkSerializer...
1 parent 2711aed commit a26bed6

File tree

3 files changed

+53
-11
lines changed

3 files changed

+53
-11
lines changed

src/PhpPalettedBlockArray.cpp

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,14 +52,31 @@ static bool palette_data_from_array(HashTable* paletteHt, std::vector<Block>& pa
5252
return true;
5353
}
5454

55-
static bool paletted_block_array_from_data(zval *return_value, zend_long bitsPerBlock, zend_string *wordArrayZstr, HashTable *paletteHt) {
55+
static bool palette_data_from_string(zend_string* paletteZstr, std::vector<Block>& palette) {
56+
if ((ZSTR_LEN(paletteZstr) % sizeof(Block)) != 0) {
57+
zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0, "palette length in bytes must be a multiple of %zu, but have %zu bytes", sizeof(Block), ZSTR_LEN(paletteZstr));
58+
return false;
59+
}
60+
61+
auto paletteEntries = ZSTR_LEN(paletteZstr) / sizeof(Block);
62+
Block* paletteValues = reinterpret_cast<Block*>(ZSTR_VAL(paletteZstr));
63+
palette.assign(paletteValues, paletteValues + paletteEntries);
64+
65+
return true;
66+
}
67+
68+
static bool paletted_block_array_from_data(zval *return_value, zend_long bitsPerBlock, zend_string *wordArrayZstr, HashTable *paletteHt, zend_string* paletteZstr) {
5669
object_init_ex(return_value, paletted_block_array_entry);
5770
paletted_block_array_obj *intern = fetch_from_zend_object<paletted_block_array_obj>(Z_OBJ_P(return_value));
5871

5972
gsl::span<uint8_t> wordArray((uint8_t*)ZSTR_VAL(wordArrayZstr), (uint8_t*)(ZSTR_VAL(wordArrayZstr) + ZSTR_LEN(wordArrayZstr)));
6073
std::vector<Block> palette;
6174

62-
if (!palette_data_from_array(paletteHt, palette)) {
75+
assert(paletteHt != nullptr && paletteZstr != nullptr);
76+
77+
if (paletteHt != nullptr && !palette_data_from_array(paletteHt, palette)) {
78+
return false;
79+
} else if (paletteZstr != nullptr && !palette_data_from_string(paletteZstr, palette)) {
6380
return false;
6481
}
6582

@@ -96,6 +113,16 @@ static void paletted_block_array_get_palette(zval *object, zval *return_value) {
96113
}
97114
}
98115

116+
static void paletted_block_array_get_palette_bytes(zval* object, zval* return_value) {
117+
paletted_block_array_obj *intern = fetch_from_zend_object<paletted_block_array_obj>(Z_OBJ_P(object));
118+
119+
auto palette = intern->container.getPalette();
120+
121+
const Block* paletteValues = palette.data();
122+
123+
ZVAL_STRINGL(return_value, reinterpret_cast<const char*>(paletteValues), palette.size_bytes());
124+
}
125+
99126
static bool paletted_block_array_set_palette(zval* object, HashTable* paletteHt) {
100127
paletted_block_array_obj* intern = fetch_from_zend_object<paletted_block_array_obj>(Z_OBJ_P(object));
101128

@@ -206,7 +233,7 @@ static int paletted_block_array_unserialize(zval *object, zend_class_entry *ce,
206233
goto end;
207234
}
208235

209-
if (!paletted_block_array_from_data(object, Z_LVAL_P(bitsPerBlock), Z_STR_P(wordArray), Z_ARRVAL_P(palette))) {
236+
if (!paletted_block_array_from_data(object, Z_LVAL_P(bitsPerBlock), Z_STR_P(wordArray), Z_ARRVAL_P(palette), nullptr)) {
210237
goto end;
211238
}
212239

@@ -251,15 +278,16 @@ PALETTED_BLOCK_ARRAY_METHOD(__construct) {
251278
PALETTED_BLOCK_ARRAY_METHOD(fromData) {
252279
zend_long bitsPerBlock = 1;
253280
zend_string *wordArrayZstr;
254-
zval *paletteZarray;
281+
HashTable* paletteHt;
282+
zend_string* paletteZstr;
255283

256284
ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 3, 3)
257285
Z_PARAM_LONG(bitsPerBlock)
258286
Z_PARAM_STR(wordArrayZstr)
259-
Z_PARAM_ARRAY(paletteZarray)
287+
Z_PARAM_ARRAY_HT_OR_STR(paletteHt, paletteZstr)
260288
ZEND_PARSE_PARAMETERS_END();
261289

262-
paletted_block_array_from_data(return_value, bitsPerBlock, wordArrayZstr, Z_ARRVAL_P(paletteZarray));
290+
paletted_block_array_from_data(return_value, bitsPerBlock, wordArrayZstr, paletteHt, paletteZstr);
263291
}
264292

265293
PALETTED_BLOCK_ARRAY_METHOD(getWordArray) {
@@ -274,6 +302,12 @@ PALETTED_BLOCK_ARRAY_METHOD(getPalette) {
274302
paletted_block_array_get_palette(getThis(), return_value);
275303
}
276304

305+
PALETTED_BLOCK_ARRAY_METHOD(getPaletteBytes) {
306+
zend_parse_parameters_none_throw();
307+
308+
paletted_block_array_get_palette_bytes(getThis(), return_value);
309+
}
310+
277311
PALETTED_BLOCK_ARRAY_METHOD(setPalette) {
278312
zval* paletteZarray;
279313

stubs/pocketmine/world/format/PalettedBlockArray.stub.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ public function __construct(int $fillEntry){}
1313
/**
1414
* @param int[] $palette
1515
*/
16-
public static function fromData(int $bitsPerBlock, string $wordArray, array $palette) : \pocketmine\world\format\PalettedBlockArray{}
16+
public static function fromData(int $bitsPerBlock, string $wordArray, array|string $palette) : \pocketmine\world\format\PalettedBlockArray{}
1717

1818
public function getWordArray() : string{}
1919

@@ -22,6 +22,12 @@ public function getWordArray() : string{}
2222
*/
2323
public function getPalette() : array{}
2424

25+
/**
26+
* Returns the palette as a byte array of serialized little-endian unsigned integers
27+
* This is faster than getPalette() since it doesn't have to turn the palette into an array
28+
*/
29+
public function getPaletteBytes() : string{}
30+
2531
/**
2632
* The input array must be the same size as the current palette
2733
* Keys are ignored. Only input order is considered.

stubs/pocketmine/world/format/PalettedBlockArray_arginfo.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* This is a generated file, edit the .stub.php file instead.
2-
* Stub hash: 2fb7da7398e7a9133d3b3e29777b3fd576b033ee */
2+
* Stub hash: 6cf9cfe99edfe236b1fd600d5684b3b14d7f465e */
33

44
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_pocketmine_world_format_PalettedBlockArray___construct, 0, 0, 1)
55
ZEND_ARG_TYPE_INFO(0, fillEntry, IS_LONG, 0)
@@ -8,7 +8,7 @@ ZEND_END_ARG_INFO()
88
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_pocketmine_world_format_PalettedBlockArray_fromData, 0, 3, pocketmine\\world\\format\\PalettedBlockArray, 0)
99
ZEND_ARG_TYPE_INFO(0, bitsPerBlock, IS_LONG, 0)
1010
ZEND_ARG_TYPE_INFO(0, wordArray, IS_STRING, 0)
11-
ZEND_ARG_TYPE_INFO(0, palette, IS_ARRAY, 0)
11+
ZEND_ARG_TYPE_MASK(0, palette, MAY_BE_ARRAY|MAY_BE_STRING, NULL)
1212
ZEND_END_ARG_INFO()
1313

1414
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_pocketmine_world_format_PalettedBlockArray_getWordArray, 0, 0, IS_STRING, 0)
@@ -17,6 +17,8 @@ ZEND_END_ARG_INFO()
1717
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_pocketmine_world_format_PalettedBlockArray_getPalette, 0, 0, IS_ARRAY, 0)
1818
ZEND_END_ARG_INFO()
1919

20+
#define arginfo_class_pocketmine_world_format_PalettedBlockArray_getPaletteBytes arginfo_class_pocketmine_world_format_PalettedBlockArray_getWordArray
21+
2022
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_pocketmine_world_format_PalettedBlockArray_setPalette, 0, 1, IS_VOID, 0)
2123
ZEND_ARG_TYPE_INFO(0, palette, IS_ARRAY, 0)
2224
ZEND_END_ARG_INFO()
@@ -52,11 +54,11 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_pocketmine_world_format_Pa
5254
ZEND_ARG_TYPE_INFO(0, bitsPerBlock, IS_LONG, 0)
5355
ZEND_END_ARG_INFO()
5456

55-
5657
ZEND_METHOD(pocketmine_world_format_PalettedBlockArray, __construct);
5758
ZEND_METHOD(pocketmine_world_format_PalettedBlockArray, fromData);
5859
ZEND_METHOD(pocketmine_world_format_PalettedBlockArray, getWordArray);
5960
ZEND_METHOD(pocketmine_world_format_PalettedBlockArray, getPalette);
61+
ZEND_METHOD(pocketmine_world_format_PalettedBlockArray, getPaletteBytes);
6062
ZEND_METHOD(pocketmine_world_format_PalettedBlockArray, setPalette);
6163
ZEND_METHOD(pocketmine_world_format_PalettedBlockArray, getMaxPaletteSize);
6264
ZEND_METHOD(pocketmine_world_format_PalettedBlockArray, getBitsPerBlock);
@@ -66,12 +68,12 @@ ZEND_METHOD(pocketmine_world_format_PalettedBlockArray, replaceAll);
6668
ZEND_METHOD(pocketmine_world_format_PalettedBlockArray, collectGarbage);
6769
ZEND_METHOD(pocketmine_world_format_PalettedBlockArray, getExpectedWordArraySize);
6870

69-
7071
static const zend_function_entry class_pocketmine_world_format_PalettedBlockArray_methods[] = {
7172
ZEND_ME(pocketmine_world_format_PalettedBlockArray, __construct, arginfo_class_pocketmine_world_format_PalettedBlockArray___construct, ZEND_ACC_PUBLIC)
7273
ZEND_ME(pocketmine_world_format_PalettedBlockArray, fromData, arginfo_class_pocketmine_world_format_PalettedBlockArray_fromData, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
7374
ZEND_ME(pocketmine_world_format_PalettedBlockArray, getWordArray, arginfo_class_pocketmine_world_format_PalettedBlockArray_getWordArray, ZEND_ACC_PUBLIC)
7475
ZEND_ME(pocketmine_world_format_PalettedBlockArray, getPalette, arginfo_class_pocketmine_world_format_PalettedBlockArray_getPalette, ZEND_ACC_PUBLIC)
76+
ZEND_ME(pocketmine_world_format_PalettedBlockArray, getPaletteBytes, arginfo_class_pocketmine_world_format_PalettedBlockArray_getPaletteBytes, ZEND_ACC_PUBLIC)
7577
ZEND_ME(pocketmine_world_format_PalettedBlockArray, setPalette, arginfo_class_pocketmine_world_format_PalettedBlockArray_setPalette, ZEND_ACC_PUBLIC)
7678
ZEND_ME(pocketmine_world_format_PalettedBlockArray, getMaxPaletteSize, arginfo_class_pocketmine_world_format_PalettedBlockArray_getMaxPaletteSize, ZEND_ACC_PUBLIC)
7779
ZEND_ME(pocketmine_world_format_PalettedBlockArray, getBitsPerBlock, arginfo_class_pocketmine_world_format_PalettedBlockArray_getBitsPerBlock, ZEND_ACC_PUBLIC)

0 commit comments

Comments
 (0)