Skip to content

Commit

Permalink
feat: implement HDR support, properly copy ArrayBuffers
Browse files Browse the repository at this point in the history
  • Loading branch information
okwasniewski committed Oct 16, 2024
1 parent 4bc852c commit 7b7110c
Show file tree
Hide file tree
Showing 8 changed files with 129 additions and 13 deletions.
49 changes: 39 additions & 10 deletions cpp/react-native-basis-universal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,26 +101,32 @@ int ReactNativeBasisUniversal::encode(jsi::Runtime &rt, jsi::Object handle, jsi:
{
// Compression succeeded, so copy the .ktx2 file bytes to the caller's buffer.
auto output = comp.get_output_basis_file();
data = reinterpret_cast<uint8_t*>(output.data());

if (!data) {
return 0;
}

auto outputBuffer = jsi::ArrayBuffer(std::move(arrayBuffer));
memcpy(outputBuffer.data(rt), output.data(), output.size());
basisFileData.setProperty(rt, jsi::PropNameID::forAscii(rt, "buffer"), outputBuffer);


// Return the file size of the .basis file in bytes.
return (uint32_t)comp.get_output_ktx2_file().size();
}
else
{
auto output = comp.get_output_basis_file();

// Compression succeeded, so copy the .basis file bytes to the caller's buffer.
data = reinterpret_cast<uint8_t*>(output.data());

if (!data) {
return 0;
}

// Compression succeeded, so copy the .basis file bytes to the caller's buffer.
auto outputBuffer = jsi::ArrayBuffer(std::move(arrayBuffer));
memcpy(outputBuffer.data(rt), output.data(), output.size());
basisFileData.setProperty(rt, jsi::PropNameID::forAscii(rt, "buffer"), outputBuffer);

// Return the file size of the .basis file in bytes.
return (uint32_t)comp.get_output_basis_file().size();
}
Expand Down Expand Up @@ -166,13 +172,11 @@ bool ReactNativeBasisUniversal::setSliceSourceImage(jsi::Runtime &rt, jsi::Objec
}
else
{
// auto arrayBufferSize = arrayBuffer.size(rt);
// auto expectedSize = width * height * sizeof(uint32_t);
// It's a raw image, so check the buffer's size.
// if (arrayBuffer.size(rt) != width * height * sizeof(uint32_t))
// {
// return false;
// }
if (arrayBuffer.size(rt) != width * height * sizeof(uint32_t))
{
return false;
}

// Copy the raw image's data into our source image.
src_img.resize(width, height);
Expand All @@ -182,6 +186,31 @@ bool ReactNativeBasisUniversal::setSliceSourceImage(jsi::Runtime &rt, jsi::Objec
return true;
}

bool ReactNativeBasisUniversal::setSliceSourceImageHDR(jsi::Runtime &rt, jsi::Object handle, int sliceIndex, jsi::Object imageArray, int width, int height, int imgType, bool ldrSrgbToLinear) {
if (!imageArray.isArrayBuffer(rt)) {
throw jsi::JSError(rt, "Image Array needs to be ArrayBuffer");
}
auto encoder = tryGetBasisEncoder(rt, handle);

auto arrayBuffer = imageArray.getArrayBuffer(rt);
auto data = arrayBuffer.data(rt);

// Resize the source_images_hdr array if necessary
if (sliceIndex >= encoder->m_params.m_source_images_hdr.size())
encoder->m_params.m_source_images_hdr.resize(sliceIndex + 1);

// Now load the source image.
imagef& src_img = encoder->m_params.m_source_images_hdr[sliceIndex];

return load_image_hdr(data,
arrayBuffer.size(rt),
src_img,
width,
height,
(hdr_image_type)imgType,
ldrSrgbToLinear);
}

void ReactNativeBasisUniversal::setPackUASTCFlags(jsi::Runtime &rt, jsi::Object handle, int flags) {
auto encoder = tryGetBasisEncoder(rt, handle);
assert((flags & cPackUASTCLevelMask) >= cPackUASTCLevelFastest);
Expand Down
1 change: 1 addition & 0 deletions cpp/react-native-basis-universal.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ class ReactNativeBasisUniversal : public NativeBasisUniversalCxxSpecJSI {
void setKTX2SRGBTransferFunc(jsi::Runtime &rt, jsi::Object handle, bool flag) override;
void setMipSRGB(jsi::Runtime &rt, jsi::Object handle, bool flag) override;
void setMipRenormalize(jsi::Runtime &rt, jsi::Object handle, bool flag) override;
bool setSliceSourceImageHDR(jsi::Runtime &rt, jsi::Object handle, int sliceIndex, jsi::Object imageArray, int width, int height, int imgType, bool ldrSrgbToLinear) override;


private:
Expand Down
6 changes: 6 additions & 0 deletions example/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1548,6 +1548,8 @@ PODS:
- React-Core
- React-jsi
- ReactTestApp-Resources (1.0.0-dev)
- RNFS (2.20.0):
- React-Core
- SocketRocket (0.7.0)
- Yoga (0.0.0)

Expand Down Expand Up @@ -1620,6 +1622,7 @@ DEPENDENCIES:
- "ReactNativeHost (from `../node_modules/@rnx-kit/react-native-host`)"
- ReactTestApp-DevSupport (from `../node_modules/react-native-test-app`)
- ReactTestApp-Resources (from `..`)
- RNFS (from `../node_modules/react-native-fs`)
- Yoga (from `../node_modules/react-native/ReactCommon/yoga`)

SPEC REPOS:
Expand Down Expand Up @@ -1760,6 +1763,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native-test-app"
ReactTestApp-Resources:
:path: ".."
RNFS:
:path: "../node_modules/react-native-fs"
Yoga:
:path: "../node_modules/react-native/ReactCommon/yoga"

Expand Down Expand Up @@ -1830,6 +1835,7 @@ SPEC CHECKSUMS:
ReactNativeHost: a27bb5af1c4d73dd3e80cc7ce295407f414e0e8c
ReactTestApp-DevSupport: ed439cce949caf074af3ae05051b4bd157ed4019
ReactTestApp-Resources: 7db90c026cccdf40cfa495705ad436ccc4d64154
RNFS: 4ac0f0ea233904cb798630b3c077808c06931688
SocketRocket: abac6f5de4d4d62d24e11868d7a2f427e0ef940d
Yoga: 055f92ad73f8c8600a93f0e25ac0b2344c3b07e6

Expand Down
3 changes: 2 additions & 1 deletion example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
"dependencies": {
"react": "18.3.1",
"react-native": "0.75.4",
"react-native-blob-jsi-helper": "^0.3.1"
"react-native-blob-jsi-helper": "^0.3.1",
"react-native-fs": "^2.20.0"
},
"devDependencies": {
"@babel/core": "^7.20.0",
Expand Down
20 changes: 18 additions & 2 deletions example/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
BasisEncoder,
} from '@callstack/react-native-basis-universal';
import { getArrayBufferForBlob } from 'react-native-blob-jsi-helper';
import RNFS from 'react-native-fs';

function arrayBufferToBase64(buffer: Uint8Array): string {
let binary = '';
Expand Down Expand Up @@ -76,11 +77,12 @@ const BasisEncoderPlayground = () => {
basisEncoder.setCreateKTX2File(true);
basisEncoder.setDebug(false);
basisEncoder.setComputeStats(false);
basisEncoder.setSliceSourceImage(
basisEncoder.setSliceSourceImageHDR(
0,
image,
imageWidth,
imageHeight,
3,
false
);
basisEncoder.setUASTC(options.uastc);
Expand Down Expand Up @@ -111,11 +113,19 @@ const BasisEncoderPlayground = () => {
basisEncoder.setMipGen(options.mipmaps);

console.log(`Starting encode with ${imageWidth}x${imageHeight} image`);
const t0 = performance.now();

const basisFileData = new Uint8Array(imageWidth * imageHeight * 4);
console.log('basisFileData hash before:', basisFileData.slice(0, 100));
const t0 = performance.now();
console.log(
'basisFileData byteLength before: ',
basisFileData.buffer.byteLength
);
const numOutputBytes = basisEncoder.encode(basisFileData);
const t1 = performance.now();

console.log('basisFileData hash after:', basisFileData.slice(0, 100));

console.log(
`Call to basisEncoder.encode took ${(t1 - t0) / 1000} seconds.`
);
Expand All @@ -127,6 +137,12 @@ const BasisEncoderPlayground = () => {
numOutputBytes
);

const path = RNFS.DocumentDirectoryPath + '/output.ktx2';
console.log(path);

const base64Data = arrayBufferToBase64(actualKTX2FileData);
await RNFS.writeFile(path, base64Data, 'base64');

console.log('actualKTX2FileData', actualKTX2FileData.buffer.byteLength);
} catch (error) {
console.error('Encoding failed:', error);
Expand Down
23 changes: 23 additions & 0 deletions src/BasisEncoder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,29 @@ export class BasisEncoder {
NativeBasisUniversal.setComputeStats(this.#nativeBasisHandle, flag);
}

setSliceSourceImageHDR(
sliceIndex: Int32,
imageArray: Uint8Array,
width: Int32,
height: Int32,
imgType: Int32,
ldrSrgbToLinear: boolean
): boolean {
if (this.#nativeBasisHandle == null) {
return false;
}

return NativeBasisUniversal.setSliceSourceImageHDR(
this.#nativeBasisHandle,
sliceIndex,
imageArray.buffer,
width,
height,
imgType,
ldrSrgbToLinear
);
}

setSliceSourceImage(
sliceIndex: Int32,
imageArray: Uint8Array,
Expand Down
9 changes: 9 additions & 0 deletions src/NativeBasisUniversal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,15 @@ export interface Spec extends TurboModule {
height: Int32,
isPng: boolean
) => boolean;
setSliceSourceImageHDR: (
handle: OpaqueNativeBasisHandle,
sliceIndex: Int32,
imageArray: UnsafeObject,
width: Int32,
height: Int32,
imgType: Int32,
ldrSrgbToLinear: boolean
) => boolean;
encode: (
handle: OpaqueNativeBasisHandle,
basisFileData: UnsafeObject
Expand Down
31 changes: 31 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4060,6 +4060,13 @@ __metadata:
languageName: node
linkType: hard

"base-64@npm:^0.1.0":
version: 0.1.0
resolution: "base-64@npm:0.1.0"
checksum: 5a42938f82372ab5392cbacc85a5a78115cbbd9dbef9f7540fa47d78763a3a8bd7d598475f0d92341f66285afd377509851a9bb5c67bbecb89686e9255d5b3eb
languageName: node
linkType: hard

"base64-js@npm:^1.3.1, base64-js@npm:^1.5.1":
version: 1.5.1
resolution: "base64-js@npm:1.5.1"
Expand Down Expand Up @@ -10847,6 +10854,7 @@ __metadata:
react-native: 0.75.4
react-native-blob-jsi-helper: ^0.3.1
react-native-builder-bob: ^0.30.2
react-native-fs: ^2.20.0
react-native-test-app: ^3.10.14
languageName: unknown
linkType: soft
Expand Down Expand Up @@ -10893,6 +10901,22 @@ __metadata:
languageName: node
linkType: hard

"react-native-fs@npm:^2.20.0":
version: 2.20.0
resolution: "react-native-fs@npm:2.20.0"
dependencies:
base-64: ^0.1.0
utf8: ^3.0.0
peerDependencies:
react-native: "*"
react-native-windows: "*"
peerDependenciesMeta:
react-native-windows:
optional: true
checksum: 0be9bb9a5c13b501d0a3006efc3aa5c0b5b211456ee04718297f4e522532f3527f1daa220bd67d3b82d819ed8fdab8f64b7d6e0d7b768c1fd1d8ec9122d94316
languageName: node
linkType: hard

"react-native-test-app@npm:^3.10.14":
version: 3.10.14
resolution: "react-native-test-app@npm:3.10.14"
Expand Down Expand Up @@ -12963,6 +12987,13 @@ __metadata:
languageName: node
linkType: hard

"utf8@npm:^3.0.0":
version: 3.0.0
resolution: "utf8@npm:3.0.0"
checksum: cb89a69ad9ab393e3eae9b25305b3ff08bebca9adc839191a34f90777eb2942f86a96369d2839925fea58f8f722f7e27031d697f10f5f39690f8c5047303e62d
languageName: node
linkType: hard

"util-deprecate@npm:^1.0.1, util-deprecate@npm:~1.0.1":
version: 1.0.2
resolution: "util-deprecate@npm:1.0.2"
Expand Down

0 comments on commit 7b7110c

Please sign in to comment.