Skip to content

Commit b9ecc62

Browse files
committed
Improve HDR render, some optimizations and bugxfixes
1 parent 273d35d commit b9ecc62

File tree

12 files changed

+394
-96
lines changed

12 files changed

+394
-96
lines changed

app/src/main/java/com/radzivon/bartoshyk/avif/MainActivity.kt

Lines changed: 16 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -27,52 +27,44 @@ package com.radzivon.bartoshyk.avif
2727

2828
import android.graphics.Bitmap
2929
import android.graphics.BitmapFactory
30-
import android.graphics.Canvas
31-
import android.graphics.Paint
3230
import android.os.Build
33-
import androidx.appcompat.app.AppCompatActivity
3431
import android.os.Bundle
3532
import android.util.Log
3633
import android.util.Size
37-
import androidx.core.graphics.scale
38-
import androidx.lifecycle.lifecycleScope
39-
import coil.ImageLoader
40-
import coil.load
41-
import com.bumptech.glide.Glide
42-
import com.bumptech.glide.load.engine.DiskCacheStrategy
43-
import com.github.awxkee.avifcoil.HeifDecoder
34+
import androidx.appcompat.app.AppCompatActivity
4435
import com.radzivon.bartoshyk.avif.coder.HeifCoder
4536
import com.radzivon.bartoshyk.avif.coder.PreferredColorConfig
4637
import com.radzivon.bartoshyk.avif.coder.ScaleMode
4738
import com.radzivon.bartoshyk.avif.coder.ToneMapper
4839
import com.radzivon.bartoshyk.avif.databinding.ActivityMainBinding
4940
import com.radzivon.bartoshyk.avif.databinding.BindingImageViewBinding
50-
import kotlinx.coroutines.Dispatchers
51-
import kotlinx.coroutines.launch
5241
import okio.FileNotFoundException
5342
import okio.buffer
5443
import okio.sink
5544
import okio.source
5645
import java.io.File
5746
import java.io.FileOutputStream
5847
import java.io.IOException
59-
import kotlin.system.measureTimeMillis
48+
6049

6150
class MainActivity : AppCompatActivity() {
6251

6352
private lateinit var binding: ActivityMainBinding
6453

65-
fun getAllFilesFromAssets(): List<String> {
54+
fun getAllFilesFromAssets(path: String = ""): List<String> {
6655
val assetManager = assets
6756
val fileList: MutableList<String> = mutableListOf()
6857

6958
try {
7059
// List all files in the "assets" folder
71-
val files = assetManager.list("") ?: arrayOf()
72-
60+
val files = assetManager.list(path) ?: arrayOf()
7361
// Add each file to the list
7462
for (file in files) {
75-
fileList.add(file)
63+
if (path.isEmpty()) {
64+
fileList.add(file)
65+
} else {
66+
fileList.add("${path}/${file}")
67+
}
7668
}
7769
} catch (e: IOException) {
7870
e.printStackTrace()
@@ -97,7 +89,11 @@ class MainActivity : AppCompatActivity() {
9789

9890
// HDR EXAMPLES - https://us.zonerama.com/williamskeaguidingphotography/Photo/1000120226/1004888131
9991
val coder = HeifCoder(this, toneMapper = ToneMapper.LOGARITHMIC)
100-
val allFiles = getAllFilesFromAssets().filter { it.contains(".avif") || it.contains(".heic") }
92+
val allFiles1 = getAllFilesFromAssets().filter { it.contains(".avif") || it.contains(".heic") }
93+
val allFiles2 = getAllFilesFromAssets(path = "hdr").filter { it.contains(".avif") || it.contains(".heic") }
94+
val allFiles = mutableListOf<String>()
95+
allFiles.addAll(allFiles2)
96+
allFiles.addAll(allFiles1)
10197
for (file in allFiles) {
10298
try {
10399
val imageView = BindingImageViewBinding.inflate(layoutInflater, binding.scrollViewContainer, false)
@@ -107,8 +103,8 @@ class MainActivity : AppCompatActivity() {
107103
if (size != null) {
108104
val bitmap = coder.decodeSampled(
109105
buffer,
110-
size.width / 2,
111-
size.height / 2,
106+
if (size.width > 1800 || size.height > 1800) size.width / 2 else size.width,
107+
if (size.width > 1800 || size.height > 1800) size.height / 2 else size.height,
112108
PreferredColorConfig.HARDWARE,
113109
ScaleMode.RESIZE
114110
)

app/src/main/res/layout/binding_image_view.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,5 +28,6 @@
2828

2929
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
3030
android:layout_width="match_parent"
31+
android:adjustViewBounds="true"
3132
android:layout_height="wrap_content"
3233
android:scaleType="fitCenter" />

avif-coder-coil/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ afterEvaluate {
4242
create<MavenPublication>("mavenJava") {
4343
groupId = "com.github.awxkee"
4444
artifactId = "avif-coder-coil"
45-
version = "1.5.9"
45+
version = "1.5.12"
4646
from(components.findByName("release"))
4747
// artifact("androidSourcesJar")
4848
}

avif-coder/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ afterEvaluate {
4242
create<MavenPublication>("mavenJava") {
4343
groupId = "com.github.awxkee"
4444
artifactId = "avif-coder"
45-
version = "1.5.9"
45+
version = "1.5.12"
4646
from(components["release"])
4747
// artifact("androidSourcesJar")
4848
}

avif-coder/src/main/cpp/JniDecoder.cpp

Lines changed: 81 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -174,32 +174,18 @@ jobject decodeImplementationNative(JNIEnv *env, jobject thiz,
174174
convertUseICC(dstARGB, stride, imageWidth, imageHeight, profile.data(),
175175
profile.size(),
176176
useBitmapHalf16Floats, &stride);
177-
} else if (colorProfile == "SMPTE_428" && hasNCLX) {
178-
float primaries[3][2] = {{static_cast<float>(nclx->color_primary_red_x),
179-
static_cast<float>(nclx->color_primary_red_y)},
180-
{static_cast<float>(nclx->color_primary_green_x),
181-
static_cast<float>(nclx->color_primary_green_y)},
182-
{static_cast<float>(nclx->color_primary_blue_x),
183-
static_cast<float>(nclx->color_primary_blue_y)}};
184-
float whitePoint[2] = {static_cast<float>(nclx->color_primary_white_x),
185-
static_cast<float>(nclx->color_primary_white_y)};
186-
ColorSpaceProfile srcProfile(primaries, whitePoint, Rec2020LumaPrimaries,
187-
DisplayP3WhitePointNits);
188-
HDRTransferAdapter hdrTransferAdapter(
189-
reinterpret_cast<uint8_t *>(dstARGB.data()),
190-
stride, imageWidth, imageHeight, useBitmapHalf16Floats,
191-
useBitmapHalf16Floats ? 16 : 8, Rec709, SMPTE428, toneMapper, &srcProfile,
192-
rec709Profile, 2.2f);
193-
hdrTransferAdapter.transfer();
194-
} else if (colorProfile == "BT2020_PQ" || colorProfile == "DISPLAY_P3_PQ" ||
195-
colorProfile == "BT2020_HLG" || colorProfile == "DISPLAY_P3_HLG") {
177+
} else if ((colorProfile == "BT2020_PQ" || colorProfile == "DISPLAY_P3_PQ" ||
178+
colorProfile == "BT2020_HLG" || colorProfile == "DISPLAY_P3_HLG" ||
179+
colorProfile.find("SMPTE_428") != std::string::npos) && hasNCLX && (nclx)) {
196180
bool isVulkanLoaded = loadVulkanRunner();
197181
bool vulkanWorkerDone = false;
198182
if (assetManager != nullptr && isVulkanLoaded) {
199183
std::string kernel = "SMPTE2084.comp.spv";
200184

201185
if (colorProfile.find("HLG") != std::string::npos) {
202186
kernel = "HLG.comp.spv";
187+
} else if (colorProfile.find("SMPTE_428") != std::string::npos) {
188+
kernel = "SMPTE428.comp.spv";
203189
}
204190

205191
float primaries[3][2] = {{static_cast<float>(nclx->color_primary_red_x),
@@ -214,13 +200,13 @@ jobject decodeImplementationNative(JNIEnv *env, jobject thiz,
214200
float lumaPrimaries[3];
215201

216202
if (colorProfile.find("BT2020") != std::string::npos) {
217-
memcpy(lumaPrimaries, Rec2020LumaPrimaries, sizeof (float) * 3);
203+
memcpy(lumaPrimaries, Rec2020LumaPrimaries, sizeof(float) * 3);
218204
} else {
219-
memcpy(lumaPrimaries, DisplayP3LumaPrimaries, sizeof (float) * 3);
205+
memcpy(lumaPrimaries, DisplayP3LumaPrimaries, sizeof(float) * 3);
220206
}
221207

222208
ColorSpaceProfile srcProfile(primaries, whitePoint, Rec2020LumaPrimaries,
223-
DisplayP3WhitePointNits);
209+
Rec2020WhitePointNits);
224210
CmsMatrix dstMatrix = CmsMatrix(rec709Profile->primaries, rec709Profile->illuminant);
225211
CmsMatrix srcMatrix = CmsMatrix(srcProfile.primaries, srcProfile.illuminant);
226212
CmsMatrix trns = dstMatrix.inverted() * srcMatrix;
@@ -230,9 +216,10 @@ jobject decodeImplementationNative(JNIEnv *env, jobject thiz,
230216
.oetfCurve = 1,
231217
};
232218

233-
memcpy(shaderData.lumaPrimaries, lumaPrimaries, sizeof (float) * 3);
219+
memcpy(shaderData.lumaPrimaries, lumaPrimaries, sizeof(float) * 3);
234220

235-
if (colorProfile == "DISPLAY_P3_PQ" || colorProfile == "DISPLAY_P3_HLG") {
221+
if (colorProfile == "DISPLAY_P3_PQ" || colorProfile == "DISPLAY_P3_HLG" ||
222+
colorProfile.find("BT2020") != std::string::npos) {
236223
shaderData.oetfCurve = 2;
237224
}
238225

@@ -262,6 +249,9 @@ jobject decodeImplementationNative(JNIEnv *env, jobject thiz,
262249

263250
if (colorProfile.find("HLG") != std::string::npos) {
264251
function = HLG;
252+
} else if (colorProfile.find("SMPTE_428") != std::string::npos) {
253+
function = SMPTE428;
254+
gammaCurve = DCIP3;
265255
}
266256
HDRTransferAdapter hdrTransferAdapter(
267257
reinterpret_cast<uint8_t *>(dstARGB.data()),
@@ -270,20 +260,76 @@ jobject decodeImplementationNative(JNIEnv *env, jobject thiz,
270260
rec709Profile, 2.2f);
271261
hdrTransferAdapter.transfer();
272262
}
273-
} else if (colorProfile == "BT2020") {
274-
convertUseICC(dstARGB, stride, imageWidth, imageHeight, &bt2020[0],
275-
sizeof(bt2020),
276-
useBitmapHalf16Floats, &stride);
277-
} else if (colorProfile == "DISPLAY_P3") {
278-
convertUseICC(dstARGB, stride, imageWidth, imageHeight, &displayP3[0],
279-
sizeof(displayP3),
280-
useBitmapHalf16Floats, &stride);
263+
} else if (colorProfile == "BT2020" || colorProfile == "BT709" ||
264+
colorProfile == "DISPLAY_P3") {
265+
bool isVulkanLoaded = loadVulkanRunner();
266+
bool vulkanWorkerDone = false;
267+
268+
ColorSpaceProfile *srcProfile = rec2020Profile;
269+
if (colorProfile == "BT709") {
270+
srcProfile = rec709Profile;
271+
}
272+
CmsMatrix dstMatrix = CmsMatrix(rec709Profile->primaries, rec709Profile->illuminant);
273+
CmsMatrix srcMatrix = CmsMatrix(srcProfile->primaries, srcProfile->illuminant);
274+
CmsMatrix trns = dstMatrix.inverted() * srcMatrix;
275+
276+
float lumaPrimaries[3];
277+
278+
if (colorProfile.find("BT2020") != std::string::npos) {
279+
memcpy(lumaPrimaries, Rec2020LumaPrimaries, sizeof(float) * 3);
280+
} else if (colorProfile.find("BT709") != std::string::npos) {
281+
memcpy(lumaPrimaries, Rec709LumaPrimaries, sizeof(float) * 3);
282+
} else {
283+
memcpy(lumaPrimaries, DisplayP3LumaPrimaries, sizeof(float) * 3);
284+
}
285+
286+
if (isVulkanLoaded) {
287+
ShaderGammaData shaderData = {
288+
.oetfCurve = 3,
289+
.gamma = 2.4,
290+
};
291+
292+
if (colorProfile.find("P3") != std::string::npos) {
293+
shaderData.gamma = 2.6f;
294+
} else if (colorProfile.find("709") != std::string::npos) {
295+
shaderData.gamma = 2.0f;
296+
}
297+
298+
memcpy(shaderData.lumaPrimaries, lumaPrimaries, sizeof(float) * 3);
299+
300+
for (int i = 0; i < 3; ++i) {
301+
for (int j = 0; j < 3; ++j) {
302+
shaderData.colorMatrix[i][j] = trns.getMatrix()[i * 3 + j];
303+
}
304+
}
305+
string kernel = "GammaOetf.comp.spv";
306+
vulkanWorkerDone = VulkanRunnerWithData(kernel, assetManager,
307+
reinterpret_cast<uint8_t *>(dstARGB.data()),
308+
imageWidth,
309+
imageHeight, stride,
310+
useBitmapHalf16Floats ? RgbaF16 : RgbaU8,
311+
reinterpret_cast<void *>(&shaderData),
312+
sizeof(ShaderGammaData));
313+
}
314+
if (!vulkanWorkerDone) {
315+
HDRTransferFunction function = GAMMA_TRANSFER;
316+
float gamma = 2.4f;
317+
if (colorProfile.find("P3") != std::string::npos) {
318+
gamma = 2.6f;
319+
} else if (colorProfile.find("709") != std::string::npos) {
320+
gamma = 2.0f;
321+
}
322+
323+
HDRTransferAdapter hdrTransferAdapter(
324+
reinterpret_cast<uint8_t *>(dstARGB.data()),
325+
stride, imageWidth, imageHeight, useBitmapHalf16Floats,
326+
useBitmapHalf16Floats ? 16 : 8, sRGB, function, toneMapper, srcProfile,
327+
rec709Profile, gamma);
328+
hdrTransferAdapter.transfer();
329+
}
281330
} else if (colorProfile == "LINEAR_SRGB") {
282331
convertUseICC(dstARGB, stride, imageWidth, imageHeight, &linearSRGB[0],
283332
sizeof(linearSRGB), useBitmapHalf16Floats, &stride);
284-
} else if (colorProfile == "BT709") {
285-
convertUseICC(dstARGB, stride, imageWidth, imageHeight, &bt709[0],
286-
sizeof(bt709), useBitmapHalf16Floats, &stride);
287333
}
288334

289335
string imageConfig = useBitmapHalf16Floats ? "RGBA_F16" : "ARGB_8888";

avif-coder/src/main/cpp/VulkanRunner.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,13 @@ struct ShaderEotfData {
4848
int oetfCurve; // curve 1 - Rec2020, 2 - P3, 3 - SRGB
4949
} ;
5050

51+
struct ShaderGammaData {
52+
float colorMatrix[3][4] = {};
53+
float lumaPrimaries[3] = {};
54+
int oetfCurve; // curve 1 - Rec2020, 2 - P3, 3 - SRGB
55+
float gamma;
56+
} ;
57+
5158
bool loadVulkanRunner();
5259

5360
typedef int (*VulkanComputeRunnerFunc)(

avif-coder/src/main/cpp/colorspace/HDRTransferAdapter.cpp

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,10 @@ namespace coder::HWY_NAMESPACE {
130130
r = SMPTE428Eotf(r);
131131
g = SMPTE428Eotf(g);
132132
b = SMPTE428Eotf(b);
133+
case GAMMA_TRANSFER:
134+
r = pow(r, gamma);
135+
g = pow(g, gamma);
136+
b = pow(b, gamma);
133137
break;
134138
}
135139

@@ -192,6 +196,10 @@ namespace coder::HWY_NAMESPACE {
192196
r = SMPTE428Eotf(r);
193197
g = SMPTE428Eotf(g);
194198
b = SMPTE428Eotf(b);
199+
case GAMMA_TRANSFER:
200+
r = pow(r, gamma);
201+
g = pow(g, gamma);
202+
b = pow(b, gamma);
195203
break;
196204
}
197205

@@ -302,29 +310,42 @@ namespace coder::HWY_NAMESPACE {
302310
VF32 pqHighB;
303311

304312
switch (function) {
305-
case PQ:
313+
case PQ: {
306314
pqLowR = ToLinearPQ(df32, rLow32, sdrReferencePoint);
307315
pqLowG = ToLinearPQ(df32, gLow32, sdrReferencePoint);
308316
pqLowB = ToLinearPQ(df32, bLow32, sdrReferencePoint);
309317
pqHighR = ToLinearPQ(df32, rHigh32, sdrReferencePoint);
310318
pqHighG = ToLinearPQ(df32, gHigh32, sdrReferencePoint);
311319
pqHighB = ToLinearPQ(df32, bHigh32, sdrReferencePoint);
320+
}
312321
break;
313-
case HLG:
322+
case HLG: {
314323
pqLowR = HLGEotf(df32, rLow32);
315324
pqLowG = HLGEotf(df32, gLow32);
316325
pqLowB = HLGEotf(df32, bLow32);
317326
pqHighR = HLGEotf(df32, rHigh32);
318327
pqHighG = HLGEotf(df32, gHigh32);
319328
pqHighB = HLGEotf(df32, bHigh32);
329+
}
320330
break;
321-
case SMPTE428:
331+
case SMPTE428: {
322332
pqLowR = SMPTE428Eotf(df32, rLow32);
323333
pqLowG = SMPTE428Eotf(df32, gLow32);
324334
pqLowB = SMPTE428Eotf(df32, bLow32);
325335
pqHighR = SMPTE428Eotf(df32, rHigh32);
326336
pqHighG = SMPTE428Eotf(df32, gHigh32);
327337
pqHighB = SMPTE428Eotf(df32, bHigh32);
338+
}
339+
break;
340+
case GAMMA_TRANSFER: {
341+
const auto level = Set(df32, gamma);
342+
pqLowR = coder::HWY_NAMESPACE::Pow(df32, rLow32, level);
343+
pqLowG = coder::HWY_NAMESPACE::Pow(df32, gLow32, level);
344+
pqLowB = coder::HWY_NAMESPACE::Pow(df32, bLow32, level);
345+
pqHighR = coder::HWY_NAMESPACE::Pow(df32, rHigh32, level);
346+
pqHighG = coder::HWY_NAMESPACE::Pow(df32, gHigh32, level);
347+
pqHighB = coder::HWY_NAMESPACE::Pow(df32, bHigh32, level);
348+
}
328349
break;
329350
default:
330351
pqLowR = rLow32;
@@ -427,20 +448,30 @@ namespace coder::HWY_NAMESPACE {
427448
T pqB;
428449

429450
switch (function) {
430-
case PQ:
451+
case PQ: {
431452
pqR = ToLinearPQ(df32, R, sdrReferencePoint);
432453
pqG = ToLinearPQ(df32, G, sdrReferencePoint);
433454
pqB = ToLinearPQ(df32, B, sdrReferencePoint);
455+
}
434456
break;
435-
case HLG:
457+
case HLG: {
436458
pqR = HLGEotf(df32, R);
437459
pqG = HLGEotf(df32, G);
438460
pqB = HLGEotf(df32, B);
461+
}
439462
break;
440-
case SMPTE428:
463+
case SMPTE428: {
441464
pqR = SMPTE428Eotf(df32, R);
442465
pqG = SMPTE428Eotf(df32, G);
443466
pqB = SMPTE428Eotf(df32, B);
467+
}
468+
break;
469+
case GAMMA_TRANSFER: {
470+
const auto level = Set(df32, gamma);
471+
pqR = coder::HWY_NAMESPACE::Pow(df32, R, level);
472+
pqG = coder::HWY_NAMESPACE::Pow(df32, G, level);
473+
pqB = coder::HWY_NAMESPACE::Pow(df32, B, level);
474+
}
444475
break;
445476
default:
446477
pqR = R;

0 commit comments

Comments
 (0)