mirror of
https://github.com/rive-app/rive-ios.git
synced 2026-01-18 17:11:28 +01:00
iOS images unpremult SIMD support
Support for SIMD instructions for unpremult First checkin, using rive::int16x4 instructions : 1 pixel at a time Further checkin, using rive::int16x4 instructions : 2 pixels at a time Last checkin, avoid computation when opaque pixels (assume there will be enough opaque pixels to warrant this) Thanks to Chris for the SIMD instructions usage in rive More checkins: move the decode and unpremult to the rive decoder - this requires modifications to build files. The benefits are we are now running tests on this path. However, there are some issues with decoding two images for tests: "../../test/assets/bad.jpg" ... Apple Preview app cannot open this image, however, the current test says that it should be not null And "../../test/assets/bad.png", Apple Preview app can load this images, however, the current test says that it should be null Diffs= e992059d6 iOS images unpremult SIMD support (#7875) Co-authored-by: rivessamr <suki@rive.app>
This commit is contained in:
@@ -1 +1 @@
|
||||
ad34dd4dae54aa071ca80c457e375c015b9497a8
|
||||
e992059d6354434e91cde562e463f51bff7eac58
|
||||
|
||||
@@ -1 +1 @@
|
||||
316bf61a8cc8299a3afc95ae9d5d255dd3281436
|
||||
af95cf4b90c3d5633b35eb6bdb0619a7180bd8b6
|
||||
|
||||
@@ -71,8 +71,6 @@
|
||||
2E54F23A2BE428990013016C /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 2E54F2392BE428990013016C /* PrivacyInfo.xcprivacy */; };
|
||||
83DE4C912AA8DD7B00B88B72 /* RenderContextManager.mm in Sources */ = {isa = PBXBuildFile; fileRef = 83DE4C902AA8DD7B00B88B72 /* RenderContextManager.mm */; };
|
||||
83DE4C932AA8DD9F00B88B72 /* RenderContextManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 83DE4C922AA8DD9F00B88B72 /* RenderContextManager.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
83DE4CA02AAA072B00B88B72 /* PlatformCGImage.mm in Sources */ = {isa = PBXBuildFile; fileRef = 83DE4C9F2AAA072B00B88B72 /* PlatformCGImage.mm */; };
|
||||
83DE4CA22AAA077200B88B72 /* PlatformCGImage.h in Headers */ = {isa = PBXBuildFile; fileRef = 83DE4CA12AAA077200B88B72 /* PlatformCGImage.h */; };
|
||||
83DE4CA72AAAE72100B88B72 /* RenderContext.h in Headers */ = {isa = PBXBuildFile; fileRef = 83DE4CA62AAAE72000B88B72 /* RenderContext.h */; };
|
||||
C34609FC27FF9114002DBCB7 /* RiveFile+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C34609FB27FF9114002DBCB7 /* RiveFile+Extensions.swift */; };
|
||||
C3468E5827EB9887008652FD /* RiveView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3468E5727EB9887008652FD /* RiveView.swift */; };
|
||||
@@ -172,8 +170,6 @@
|
||||
2E54F2392BE428990013016C /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
|
||||
83DE4C902AA8DD7B00B88B72 /* RenderContextManager.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = RenderContextManager.mm; path = Source/Renderer/RenderContextManager.mm; sourceTree = SOURCE_ROOT; };
|
||||
83DE4C922AA8DD9F00B88B72 /* RenderContextManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RenderContextManager.h; sourceTree = "<group>"; };
|
||||
83DE4C9F2AAA072B00B88B72 /* PlatformCGImage.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = PlatformCGImage.mm; sourceTree = "<group>"; };
|
||||
83DE4CA12AAA077200B88B72 /* PlatformCGImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PlatformCGImage.h; sourceTree = "<group>"; };
|
||||
83DE4CA62AAAE72000B88B72 /* RenderContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RenderContext.h; sourceTree = "<group>"; };
|
||||
C34609FB27FF9114002DBCB7 /* RiveFile+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RiveFile+Extensions.swift"; sourceTree = "<group>"; };
|
||||
C3468E5727EB9887008652FD /* RiveView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RiveView.swift; sourceTree = "<group>"; };
|
||||
@@ -230,7 +226,6 @@
|
||||
046FB801264EB632000129B1 /* include */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
83DE4CA12AAA077200B88B72 /* PlatformCGImage.h */,
|
||||
C9C741F224FC510200EF9516 /* Rive.h */,
|
||||
046FB7E7264EAA5F000129B1 /* RiveFile.h */,
|
||||
046FB7EC264EAA60000129B1 /* RiveArtboard.h */,
|
||||
@@ -317,7 +312,6 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
046FB801264EB632000129B1 /* include */,
|
||||
83DE4C9F2AAA072B00B88B72 /* PlatformCGImage.mm */,
|
||||
C9C741F324FC510200EF9516 /* Rive.mm */,
|
||||
046FB7EF264EAA60000129B1 /* RiveFile.mm */,
|
||||
046FB7E2264EAA5E000129B1 /* RiveArtboard.mm */,
|
||||
@@ -413,7 +407,6 @@
|
||||
046FB7F7264EAA60000129B1 /* RiveFile.h in Headers */,
|
||||
046FB7FC264EAA61000129B1 /* RiveArtboard.h in Headers */,
|
||||
2A7079352726277C00C035A1 /* rive_renderer_view.hh in Headers */,
|
||||
83DE4CA22AAA077200B88B72 /* PlatformCGImage.h in Headers */,
|
||||
83DE4C932AA8DD9F00B88B72 /* RenderContextManager.h in Headers */,
|
||||
046FB800264EAA61000129B1 /* RiveStateMachineInstance.h in Headers */,
|
||||
043025FA2AFA860E00320F2E /* FileAssetLoaderAdapter.hpp in Headers */,
|
||||
@@ -557,7 +550,6 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
83DE4CA02AAA072B00B88B72 /* PlatformCGImage.mm in Sources */,
|
||||
2A707937272628AD00C035A1 /* rive_renderer_view.mm in Sources */,
|
||||
C34609FC27FF9114002DBCB7 /* RiveFile+Extensions.swift in Sources */,
|
||||
C3468E5827EB9887008652FD /* RiveView.swift in Sources */,
|
||||
@@ -800,6 +792,7 @@
|
||||
"-lrive_yoga",
|
||||
"-lrive_pls_renderer",
|
||||
"-lrive_cg_renderer",
|
||||
"-lrive_decoders",
|
||||
);
|
||||
"OTHER_LDFLAGS[sdk=iphonesimulator*]" = (
|
||||
"-lrive_sim",
|
||||
@@ -808,6 +801,7 @@
|
||||
"-lrive_yoga_sim",
|
||||
"-lrive_pls_renderer_sim",
|
||||
"-lrive_cg_renderer_sim",
|
||||
"-lrive_decoders_sim",
|
||||
);
|
||||
"OTHER_LDFLAGS[sdk=macosx*]" = (
|
||||
"-lrive_macos",
|
||||
@@ -816,6 +810,7 @@
|
||||
"-lrive_yoga_macos",
|
||||
"-lrive_pls_renderer_macos",
|
||||
"-lrive_cg_renderer_macos",
|
||||
"-lrive_decoders_macos",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = rive.app.ios.runtime.RiveRuntime;
|
||||
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
|
||||
@@ -885,6 +880,7 @@
|
||||
"-lrive_yoga",
|
||||
"-lrive_pls_renderer",
|
||||
"-lrive_cg_renderer",
|
||||
"-lrive_decoders",
|
||||
);
|
||||
"OTHER_LDFLAGS[sdk=iphonesimulator*]" = (
|
||||
"-lrive_sim",
|
||||
@@ -893,6 +889,7 @@
|
||||
"-lrive_yoga_sim",
|
||||
"-lrive_pls_renderer_sim",
|
||||
"-lrive_cg_renderer_sim",
|
||||
"-lrive_decoders_sim",
|
||||
);
|
||||
"OTHER_LDFLAGS[sdk=macosx*]" = (
|
||||
"-lrive_macos",
|
||||
@@ -901,6 +898,7 @@
|
||||
"-lrive_yoga_macos",
|
||||
"-lrive_pls_renderer_macos",
|
||||
"-lrive_cg_renderer_macos",
|
||||
"-lrive_decoders_macos",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = rive.app.ios.runtime.RiveRuntime;
|
||||
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
/*
|
||||
* Copyright 2023 Rive
|
||||
*/
|
||||
|
||||
#import <PlatformCGImage.h>
|
||||
#include "rive/core/type_conversions.hpp"
|
||||
#include "utils/auto_cf.hpp"
|
||||
|
||||
#include <TargetConditionals.h>
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
#include <CoreGraphics/CoreGraphics.h>
|
||||
#include <ImageIO/ImageIO.h>
|
||||
#elif TARGET_OS_MAC
|
||||
#include <ApplicationServices/ApplicationServices.h>
|
||||
#endif
|
||||
|
||||
bool PlatformCGImageDecode(const uint8_t* encodedBytes,
|
||||
size_t encodedSizeInBytes,
|
||||
PlatformCGImage* platformImage)
|
||||
{
|
||||
AutoCF data = CFDataCreate(kCFAllocatorDefault, encodedBytes, encodedSizeInBytes);
|
||||
if (!data)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
AutoCF source = CGImageSourceCreateWithData(data, nullptr);
|
||||
if (!source)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
AutoCF image = CGImageSourceCreateImageAtIndex(source, 0, nullptr);
|
||||
if (!image)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isOpaque = false;
|
||||
switch (CGImageGetAlphaInfo(image.get()))
|
||||
{
|
||||
case kCGImageAlphaNone:
|
||||
case kCGImageAlphaNoneSkipFirst:
|
||||
case kCGImageAlphaNoneSkipLast:
|
||||
isOpaque = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
const size_t width = CGImageGetWidth(image);
|
||||
const size_t height = CGImageGetHeight(image);
|
||||
const size_t rowBytes = width * 4; // 4 bytes per pixel
|
||||
const size_t size = rowBytes * height;
|
||||
|
||||
const size_t bitsPerComponent = 8;
|
||||
CGBitmapInfo cgInfo = kCGBitmapByteOrder32Big; // rgba
|
||||
if (isOpaque)
|
||||
{
|
||||
cgInfo |= kCGImageAlphaNoneSkipLast;
|
||||
}
|
||||
else
|
||||
{
|
||||
cgInfo |= kCGImageAlphaPremultipliedLast;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> pixels;
|
||||
pixels.resize(size);
|
||||
|
||||
AutoCF cs = CGColorSpaceCreateDeviceRGB();
|
||||
AutoCF cg =
|
||||
CGBitmapContextCreate(pixels.data(), width, height, bitsPerComponent, rowBytes, cs, cgInfo);
|
||||
if (!cg)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
CGContextSetBlendMode(cg, kCGBlendModeCopy);
|
||||
CGContextDrawImage(cg, CGRectMake(0, 0, width, height), image);
|
||||
|
||||
platformImage->width = rive::castTo<uint32_t>(width);
|
||||
platformImage->height = rive::castTo<uint32_t>(height);
|
||||
platformImage->opaque = isOpaque;
|
||||
platformImage->pixels = std::move(pixels);
|
||||
return true;
|
||||
}
|
||||
@@ -8,8 +8,6 @@
|
||||
#import <RivePrivateHeaders.h>
|
||||
#import <RiveFactory.h>
|
||||
|
||||
#import <PlatformCGImage.h>
|
||||
|
||||
#include "utils/auto_cf.hpp"
|
||||
#include "cg_factory.hpp"
|
||||
#include "cg_renderer.hpp"
|
||||
@@ -54,44 +52,8 @@ static std::unique_ptr<rive::pls::PLSRenderContext> make_pls_context_native(id<M
|
||||
NSLog(@"error: GPU is not Apple family");
|
||||
return nullptr;
|
||||
}
|
||||
class PLSRenderContextNativeImpl : public rive::pls::PLSRenderContextMetalImpl
|
||||
{
|
||||
public:
|
||||
PLSRenderContextNativeImpl(id<MTLDevice> gpu) :
|
||||
PLSRenderContextMetalImpl(gpu, ContextOptions())
|
||||
{}
|
||||
|
||||
protected:
|
||||
rive::rcp<rive::pls::PLSTexture> decodeImageTexture(
|
||||
rive::Span<const uint8_t> encodedBytes) override
|
||||
{
|
||||
PlatformCGImage image;
|
||||
if (!PlatformCGImageDecode(encodedBytes.data(), encodedBytes.size(), &image))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// CG only supports premultiplied alpha. Unmultiply now.
|
||||
size_t imageSizeInBytes = image.height * image.width * 4;
|
||||
for (size_t i = 0; i < imageSizeInBytes; i += 4)
|
||||
{
|
||||
auto alpha = image.pixels[i + 3];
|
||||
if (alpha != 0.0f)
|
||||
{
|
||||
auto alphaFactor = 255.0f / alpha;
|
||||
for (size_t j = 0; j < 3; j++)
|
||||
{
|
||||
image.pixels[i + j] *= alphaFactor;
|
||||
}
|
||||
}
|
||||
}
|
||||
uint32_t mipLevelCount = rive::math::msb(image.height | image.width);
|
||||
return makeImageTexture(image.width, image.height, mipLevelCount, image.pixels.data());
|
||||
}
|
||||
};
|
||||
auto plsContextImpl =
|
||||
std::unique_ptr<PLSRenderContextNativeImpl>(new PLSRenderContextNativeImpl(gpu));
|
||||
return std::make_unique<rive::pls::PLSRenderContext>(std::move(plsContextImpl));
|
||||
return rive::pls::PLSRenderContextMetalImpl::MakeContext(
|
||||
gpu, rive::pls::PLSRenderContextMetalImpl::ContextOptions());
|
||||
}
|
||||
|
||||
- (instancetype)init
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
/*
|
||||
* Copyright 2023 Rive
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
// Represents raw, premultiplied, RGBA image data with tightly packed rows (width * 4 bytes).
|
||||
struct PlatformCGImage
|
||||
{
|
||||
uint32_t width = 0;
|
||||
uint32_t height = 0;
|
||||
bool opaque = false;
|
||||
std::vector<uint8_t> pixels;
|
||||
};
|
||||
|
||||
// Decodes the given bytes into 'platformImage'.
|
||||
//
|
||||
// Returns false and leaves 'platformImage' unchaged on failure.
|
||||
[[nodiscard]] bool PlatformCGImageDecode(const uint8_t* encodedBytes,
|
||||
size_t encodedSizeInBytes,
|
||||
PlatformCGImage* platformImage);
|
||||
@@ -57,13 +57,21 @@ build_runtime() {
|
||||
|
||||
# Build rive_pls_renderer.
|
||||
pushd $RIVE_PLS_DIR
|
||||
premake5 --config=$1 --out=out/iphoneos_$1 --arch=universal --scripts=$RIVE_RUNTIME_DIR/build --file=premake5_pls_renderer.lua --no-rive-decoders --os=ios gmake2
|
||||
premake5 --config=$1 --out=out/iphoneos_$1 --arch=universal --scripts=$RIVE_RUNTIME_DIR/build --file=premake5_pls_renderer.lua --os=ios gmake2
|
||||
make -C out/iphoneos_$1 clean
|
||||
make -C out/iphoneos_$1 -j12 rive_pls_renderer
|
||||
popd
|
||||
cp -r $RIVE_PLS_DIR/out/iphoneos_$1/librive_pls_renderer.a $DEV_SCRIPT_DIR/../dependencies/$1/librive_pls_renderer.a
|
||||
$DEV_SCRIPT_DIR/strip_static_lib.sh $DEV_SCRIPT_DIR/../dependencies/$1/librive_pls_renderer.a
|
||||
cp -r $RIVE_PLS_DIR/include $DEV_SCRIPT_DIR/../dependencies/includes/pls
|
||||
|
||||
# Build rive_decoders.
|
||||
pushd $RIVE_RUNTIME_DIR/decoders
|
||||
premake5 --file=premake5_v2.lua --config=$1 --out=out/iphoneos_$1 --arch=universal --scripts=$RIVE_RUNTIME_DIR/build --os=ios gmake2
|
||||
make -C out/iphoneos_$1 clean
|
||||
make -C out/iphoneos_$1 -j12 rive_decoders
|
||||
popd
|
||||
cp -r $RIVE_RUNTIME_DIR/decoders/out/iphoneos_$1/librive_decoders.a $DEV_SCRIPT_DIR/../dependencies/$1/librive_decoders.a
|
||||
}
|
||||
|
||||
build_runtime_sim() {
|
||||
@@ -90,13 +98,21 @@ build_runtime_sim() {
|
||||
|
||||
# Build rive_pls_renderer.
|
||||
pushd $RIVE_PLS_DIR
|
||||
premake5 --config=$1 --out=out/iphonesimulator_$1 --arch=universal --scripts=$RIVE_RUNTIME_DIR/build --file=premake5_pls_renderer.lua --no-rive-decoders --os=ios --variant=emulator gmake2
|
||||
premake5 --config=$1 --out=out/iphonesimulator_$1 --arch=universal --scripts=$RIVE_RUNTIME_DIR/build --file=premake5_pls_renderer.lua --os=ios --variant=emulator gmake2
|
||||
make -C out/iphonesimulator_$1 clean
|
||||
make -C out/iphonesimulator_$1 -j12 rive_pls_renderer
|
||||
popd
|
||||
cp -r $RIVE_PLS_DIR/out/iphonesimulator_$1/librive_pls_renderer.a $DEV_SCRIPT_DIR/../dependencies/$1/librive_pls_renderer_sim.a
|
||||
$DEV_SCRIPT_DIR/strip_static_lib_fat.sh $DEV_SCRIPT_DIR/../dependencies/$1/librive_pls_renderer_sim.a arm64 x86_64
|
||||
cp -r $RIVE_PLS_DIR/include $DEV_SCRIPT_DIR/../dependencies/includes/pls
|
||||
|
||||
# Build rive_decoders.
|
||||
pushd $RIVE_RUNTIME_DIR/decoders
|
||||
premake5 --file=premake5_v2.lua --config=$1 --out=out/iphonesimulator_$1 --arch=universal --scripts=$RIVE_RUNTIME_DIR/build --os=ios --variant=emulator gmake2
|
||||
make -C out/iphonesimulator_$1 clean
|
||||
make -C out/iphonesimulator_$1 -j12 rive_decoders
|
||||
popd
|
||||
cp -r $RIVE_RUNTIME_DIR/decoders/out/iphonesimulator_$1/librive_decoders.a $DEV_SCRIPT_DIR/../dependencies/$1/librive_decoders_sim.a
|
||||
}
|
||||
|
||||
build_runtime_macosx() {
|
||||
@@ -122,13 +138,21 @@ build_runtime_macosx() {
|
||||
|
||||
# Build rive_pls_renderer.
|
||||
pushd $RIVE_PLS_DIR
|
||||
premake5 --config=$1 --arch=universal --scripts=$RIVE_RUNTIME_DIR/build --file=premake5_pls_renderer.lua --no-rive-decoders --os=macosx gmake2
|
||||
premake5 --config=$1 --arch=universal --scripts=$RIVE_RUNTIME_DIR/build --file=premake5_pls_renderer.lua --os=macosx gmake2
|
||||
make -C out/$1 clean
|
||||
make -C out/$1 -j12 rive_pls_renderer
|
||||
popd
|
||||
cp -r $RIVE_PLS_DIR/out/$1/librive_pls_renderer.a $DEV_SCRIPT_DIR/../dependencies/$1/librive_pls_renderer_macos.a
|
||||
$DEV_SCRIPT_DIR/strip_static_lib_fat.sh $DEV_SCRIPT_DIR/../dependencies/$1/librive_pls_renderer_macos.a arm64 x86_64
|
||||
cp -r $RIVE_PLS_DIR/include $DEV_SCRIPT_DIR/../dependencies/includes/pls
|
||||
|
||||
# Build rive_decoders.
|
||||
pushd $RIVE_RUNTIME_DIR/decoders
|
||||
premake5 --file=premake5_v2.lua --config=$1 --out=out/$1 --arch=universal --scripts=$RIVE_RUNTIME_DIR/build --os=macosx gmake2
|
||||
make -C out/$1 clean
|
||||
make -C out/$1 -j12 rive_decoders
|
||||
popd
|
||||
cp -r $RIVE_RUNTIME_DIR/decoders/out/$1/librive_decoders.a $DEV_SCRIPT_DIR/../dependencies/$1/librive_decoders_macos.a
|
||||
}
|
||||
|
||||
usage() {
|
||||
|
||||
Submodule submodules/rive-cpp updated: f0647c10a1...a8b7f00bed
Reference in New Issue
Block a user