Skip to content

Commit

Permalink
Merge pull request #1 from dumganhar/385-set-instance-attribute
Browse files Browse the repository at this point in the history
Fix Model::setInstancedAttribute and SubModule::setInstancedAttribute.
  • Loading branch information
GengineJS authored Nov 15, 2024
2 parents 559c119 + 21d4d42 commit c321e5a
Show file tree
Hide file tree
Showing 7 changed files with 76 additions and 78 deletions.
40 changes: 9 additions & 31 deletions native/cocos/bindings/manual/jsb_scene_manual.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -677,48 +677,26 @@ static bool js_Model_setInstancedAttribute(se::State &s) // NOLINT(readability-i
if (val.toObject()->isArray()) {
uint32_t len = 0;
val.toObject()->getArrayLength(&len);

cc::Float32Array value(len);

se::Value dataVal;
ccstd::array<float, 64> stackData;
float *pData = nullptr;
bool needFree = false;

if (len <= static_cast<uint32_t>(stackData.size())) {
pData = stackData.data();
} else {
pData = static_cast<float *>(CC_MALLOC(len));
needFree = true;
}

for (uint32_t i = 0; i < len; ++i) {
ok = val.toObject()->getArrayElement(i, &dataVal);
CC_ASSERT(ok && dataVal.isNumber());
pData[i] = dataVal.toFloat();
value[i] = dataVal.toFloat();
}

cobj->setInstancedAttribute(name, pData, len);

if (needFree) {
CC_FREE(pData);
}
cobj->setInstancedAttribute(name, value);
return true;
}

if (val.toObject()->isTypedArray()) {
se::Object::TypedArrayType type = val.toObject()->getTypedArrayType();
switch (type) {
case se::Object::TypedArrayType::FLOAT32: {
uint8_t *data = nullptr;
size_t byteCount = 0;
if (val.toObject()->getTypedArrayData(&data, &byteCount) && data != nullptr && byteCount > 0) {
cobj->setInstancedAttribute(name, reinterpret_cast<const float *>(data), static_cast<uint32_t>(byteCount));
}
} break;

default:
// FIXME:
CC_ABORT();
break;
cc::TypedArray arr;
ok = sevalue_to_native(val, &arr);
SE_PRECONDITION2(ok, false, "Error processing arguments");
if (ok) {
cobj->setInstancedAttribute(name, arr);
}
return true;
}
Expand Down
59 changes: 59 additions & 0 deletions native/cocos/core/TypedArray.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,4 +121,63 @@ void setTypedArrayValue(TypedArray &arr, uint32_t idx, const TypedArrayElementTy
#undef TYPEDARRAY_SET_VALUE
}

void copyTypedArray(TypedArray &dst, uint32_t dstOffset, const TypedArray &src) {
uint32_t srcLength = getTypedArrayLength(src);
uint32_t dstLength = getTypedArrayLength(dst);
uint32_t srcBytesPerElement = getTypedArrayBytesPerElement(src);
uint32_t dstBytesPerElement = getTypedArrayBytesPerElement(dst);

// Ensure the destination array can fit the data starting from the given offset
CC_ASSERT(dstOffset + srcLength <= dstLength);

// Optimization: If src and dst are of the same type, use memcpy for efficiency
#define COPY_TYPED_ARRAY_MEMCPY(type) \
do { \
auto *srcArray = ccstd::get_if<type>(&src); \
auto *dstArray = ccstd::get_if<type>(&dst); \
if (srcArray != nullptr && dstArray != nullptr) { \
memcpy(&(*dstArray)[dstOffset], &(*srcArray)[0], \
srcLength * srcBytesPerElement); \
return; \
} \
} while (false)

COPY_TYPED_ARRAY_MEMCPY(Float32Array);
COPY_TYPED_ARRAY_MEMCPY(Uint32Array);
COPY_TYPED_ARRAY_MEMCPY(Uint16Array);
COPY_TYPED_ARRAY_MEMCPY(Uint8Array);
COPY_TYPED_ARRAY_MEMCPY(Int32Array);
COPY_TYPED_ARRAY_MEMCPY(Int16Array);
COPY_TYPED_ARRAY_MEMCPY(Int8Array);
COPY_TYPED_ARRAY_MEMCPY(Float64Array);

#undef COPY_TYPED_ARRAY_MEMCPY

// Cross-type copy: Use a loop for element-wise copying with type conversion
#define COPY_TYPED_ARRAY_TO_DEST(type) \
do { \
auto *dstArray = ccstd::get_if<type>(&dst); \
if (dstArray != nullptr) { \
for (uint32_t i = 0; i < srcLength; ++i) { \
(*dstArray)[dstOffset + i] = getTypedArrayValue<type::value_type>(src, i); \
} \
return; \
} \
} while (false)

COPY_TYPED_ARRAY_TO_DEST(Float32Array);
COPY_TYPED_ARRAY_TO_DEST(Uint32Array);
COPY_TYPED_ARRAY_TO_DEST(Uint16Array);
COPY_TYPED_ARRAY_TO_DEST(Uint8Array);
COPY_TYPED_ARRAY_TO_DEST(Int32Array);
COPY_TYPED_ARRAY_TO_DEST(Int16Array);
COPY_TYPED_ARRAY_TO_DEST(Int8Array);
COPY_TYPED_ARRAY_TO_DEST(Float64Array);

#undef COPY_TYPED_ARRAY_TO_DEST

// If this point is reached, the destination type is unsupported
CC_ASSERTF(false, "Unsupported TypedArray type for destination");
}

} // namespace cc
2 changes: 2 additions & 0 deletions native/cocos/core/TypedArray.h
Original file line number Diff line number Diff line change
Expand Up @@ -395,4 +395,6 @@ T getTypedArrayElementValue(const TypedArrayElementType &element) {
return 0;
}

void copyTypedArray(TypedArray &dst, uint32_t dstOffset, const TypedArray &src);

} // namespace cc
4 changes: 2 additions & 2 deletions native/cocos/scene/Model.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -707,9 +707,9 @@ void Model::updateReflectionProbeId() {
_localDataUpdated = true;
}

void Model::setInstancedAttribute(const ccstd::string &name, const float *value, uint32_t byteCount) {
void Model::setInstancedAttribute(const ccstd::string &name, const TypedArray &value) {
for (const auto &subModel : _subModels) {
subModel->setInstancedAttribute(name, value, byteCount);
subModel->setInstancedAttribute(name, value);
}
}
void Model::setReflectionProbeType(UseReflectionProbeType val) {
Expand Down
2 changes: 1 addition & 1 deletion native/cocos/scene/Model.h
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ class Model : public RefCounted {
void onMacroPatchesStateChanged();
void onGeometryChanged();
void setSubModelMesh(index_t idx, RenderingSubMesh *subMesh) const;
void setInstancedAttribute(const ccstd::string &name, const float *value, uint32_t byteCount);
void setInstancedAttribute(const ccstd::string &name, const TypedArray &value);
void updateWorldBound();
void updateWorldBoundsForJSSkinningModel(const Vec3 &min, const Vec3 &max);
void updateWorldBoundsForJSBakedSkinningModel(geometry::AABB *aabb);
Expand Down
45 changes: 2 additions & 43 deletions native/cocos/scene/SubModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -362,48 +362,7 @@ void SubModel::setSubMesh(RenderingSubMesh *subMesh) {
_subMesh = subMesh;
}

template<typename T>
void copyInstancedData(const T& view, const float* value, uint32_t byteCount) {
auto* dstData = view.buffer()->getData() + view.byteOffset();
uint32_t bLength;
if constexpr (std::is_same_v<T, Float32Array>) {
bLength = byteCount * sizeof(float_t);
} else if constexpr (std::is_same_v<T, Uint16Array>) {
bLength = byteCount * sizeof(uint16_t);
} else if constexpr (std::is_same_v<T, Int16Array>) {
bLength = byteCount * sizeof(int16_t);
} else if constexpr (std::is_same_v<T, Uint32Array>) {
bLength = byteCount * sizeof(uint32_t);
} else if constexpr (std::is_same_v<T, Int32Array>) {
bLength = byteCount * sizeof(int32_t);
} else if constexpr (std::is_same_v<T, Uint8Array>) {
bLength = byteCount * sizeof(uint8_t);
} else if constexpr (std::is_same_v<T, Int8Array>) {
bLength = byteCount * sizeof(int8_t);
}
CC_ASSERT(bLength <= view.byteLength());
memcpy(dstData, value, bLength);
}

void handleTypedArray(const cc::TypedArray& view, const float* value, uint32_t byteCount) {
if (ccstd::holds_alternative<Float32Array>(view)) {
copyInstancedData(ccstd::get<Float32Array>(view), value, byteCount);
} else if (ccstd::holds_alternative<Uint16Array>(view)) {
copyInstancedData(ccstd::get<Uint16Array>(view), value, byteCount);
} else if (ccstd::holds_alternative<Int16Array>(view)) {
copyInstancedData(ccstd::get<Int16Array>(view), value, byteCount);
} else if (ccstd::holds_alternative<Uint32Array>(view)) {
copyInstancedData(ccstd::get<Uint32Array>(view), value, byteCount);
} else if (ccstd::holds_alternative<Int32Array>(view)) {
copyInstancedData(ccstd::get<Int32Array>(view), value, byteCount);
} else if (ccstd::holds_alternative<Uint8Array>(view)) {
copyInstancedData(ccstd::get<Uint8Array>(view), value, byteCount);
} else if (ccstd::holds_alternative<Int8Array>(view)) {
copyInstancedData(ccstd::get<Int8Array>(view), value, byteCount);
}
}

void SubModel::setInstancedAttribute(const ccstd::string &name, const float *value, uint32_t byteCount) {
void SubModel::setInstancedAttribute(const ccstd::string &name, const TypedArray &value) {
const auto &attributes = _instancedAttributeBlock.attributes;
auto &views = _instancedAttributeBlock.views;
for (size_t i = 0, len = attributes.size(); i < len; ++i) {
Expand All @@ -417,7 +376,7 @@ void SubModel::setInstancedAttribute(const ccstd::string &name, const float *val
case gfx::FormatType::INT:
case gfx::FormatType::FLOAT:
case gfx::FormatType::UFLOAT: {
handleTypedArray(views[i], value, byteCount);
copyTypedArray(views[i], 0, value);
} break;
case gfx::FormatType::NONE:
default:
Expand Down
2 changes: 1 addition & 1 deletion native/cocos/scene/SubModel.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ class SubModel : public RefCounted {
void setSubMesh(RenderingSubMesh *subMesh);
inline void setInstancedWorldMatrixIndex(int32_t worldMatrixIndex) { _instancedWorldMatrixIndex = worldMatrixIndex; }
inline void setInstancedSHIndex(int32_t index) { _instancedSHIndex = index; }
void setInstancedAttribute(const ccstd::string &name, const float *value, uint32_t byteCount);
void setInstancedAttribute(const ccstd::string &name, const TypedArray &value);

inline gfx::DescriptorSet *getDescriptorSet() const { return _descriptorSet; }
inline gfx::DescriptorSet *getWorldBoundDescriptorSet() const { return _worldBoundDescriptorSet; }
Expand Down

0 comments on commit c321e5a

Please sign in to comment.