Skip to content

Commit 395017e

Browse files
authored
Merge pull request #23 from wx257osn2/add-test-with-suite
Fix edge case in decoder when very first OP is QOI_OP_RUN / Add CI with official test suite
2 parents be83dde + 9c3a254 commit 395017e

File tree

4 files changed

+134
-21
lines changed

4 files changed

+134
-21
lines changed

.github/workflows/linux.yml

+40-6
Original file line numberDiff line numberDiff line change
@@ -29,17 +29,51 @@ jobs:
2929
- id: cached
3030
uses: andstor/file-existence-action@v3
3131
with:
32-
files: images
33-
- name: get benchmark suite
32+
files: "images, qoi_test_images"
33+
- name: get test/benchmark suite
3434
if: steps.cached.outputs.files_exists == 'false'
3535
shell: bash
36-
run: curl https://qoiformat.org/benchmark/qoi_benchmark_suite.tar | tar x
36+
run: |
37+
curl -O https://qoiformat.org/qoi_test_images.zip
38+
unzip qoi_test_images.zip
39+
rm qoi_test_images.zip
40+
curl https://qoiformat.org/benchmark/qoi_benchmark_suite.tar | tar x
41+
- name: build reference qoiconv
42+
shell: bash
43+
run: |
44+
pushd .dependencies/qoi
45+
ln -s ../stb/stb_image.h .
46+
ln -s ../stb/stb_image_write.h .
47+
make conv
48+
popd
49+
mv .dependencies/qoi/qoiconv bin/qoiconv_orig
3750
- name: build
3851
shell: bash
3952
run: CXX=clang++-17 make -j
53+
- name: test
54+
shell: bash
55+
run: |
56+
pushd qoi_test_images
57+
mkdir -p /tmp/qoixx
58+
mkdir -p /tmp/qoi
59+
for i in ./*.qoi; do
60+
# test decode
61+
../bin/qoiconv ${i} /tmp/qoixx/${i%.*}.png
62+
../bin/qoiconv_orig ${i} /tmp/qoi/${i%.*}.png
63+
diff /tmp/qoi{,xx}/${i%.*}.png
64+
done
65+
rm -rf /tmp/qoixx/*.png
66+
rm -rf /tmp/qoi/*.png
67+
for i in ./*.png; do
68+
# test encode
69+
../bin/qoiconv ${i} /tmp/qoixx/${i%.*}.qoi
70+
../bin/qoiconv_orig /tmp/qoixx/${i%.*}.qoi /tmp/qoixx/${i}
71+
../bin/qoiconv_orig ${i} /tmp/qoi/${i%.*}.qoi
72+
../bin/qoiconv_orig /tmp/qoi/${i%.*}.qoi /tmp/qoi/${i}
73+
diff /tmp/qoi{,xx}/${i}
74+
done
75+
popd
76+
bin/test
4077
- name: run
4178
shell: bash
4279
run: bin/qoibench 1 images --noreference --nowarmup
43-
- name: test
44-
shell: bash
45-
run: bin/test

.github/workflows/mac.yml

+40-6
Original file line numberDiff line numberDiff line change
@@ -23,17 +23,51 @@ jobs:
2323
- id: cached
2424
uses: andstor/file-existence-action@v3
2525
with:
26-
files: images
27-
- name: get benchmark suite
26+
files: "images, qoi_test_images"
27+
- name: get test/benchmark suite
2828
if: steps.cached.outputs.files_exists == 'false'
2929
shell: bash
30-
run: curl https://qoiformat.org/benchmark/qoi_benchmark_suite.tar | tar x
30+
run: |
31+
curl -O https://qoiformat.org/qoi_test_images.zip
32+
unzip qoi_test_images.zip
33+
rm qoi_test_images.zip
34+
curl https://qoiformat.org/benchmark/qoi_benchmark_suite.tar | tar x
35+
- name: build reference qoiconv
36+
shell: bash
37+
run: |
38+
pushd .dependencies/qoi
39+
ln -s ../stb/stb_image.h .
40+
ln -s ../stb/stb_image_write.h .
41+
make conv
42+
popd
43+
mv .dependencies/qoi/qoiconv bin/qoiconv_orig
3144
- name: build
3245
shell: bash
3346
run: CXX=$(brew --prefix llvm@17)/bin/clang++ make -j
47+
- name: test
48+
shell: bash
49+
run: |
50+
pushd qoi_test_images
51+
mkdir -p /tmp/qoixx
52+
mkdir -p /tmp/qoi
53+
for i in ./*.qoi; do
54+
# test decode
55+
../bin/qoiconv ${i} /tmp/qoixx/${i%.*}.png
56+
../bin/qoiconv_orig ${i} /tmp/qoi/${i%.*}.png
57+
diff /tmp/qoi{,xx}/${i%.*}.png
58+
done
59+
rm -rf /tmp/qoixx/*.png
60+
rm -rf /tmp/qoi/*.png
61+
for i in ./*.png; do
62+
# test encode
63+
../bin/qoiconv ${i} /tmp/qoixx/${i%.*}.qoi
64+
../bin/qoiconv_orig /tmp/qoixx/${i%.*}.qoi /tmp/qoixx/${i}
65+
../bin/qoiconv_orig ${i} /tmp/qoi/${i%.*}.qoi
66+
../bin/qoiconv_orig /tmp/qoi/${i%.*}.qoi /tmp/qoi/${i}
67+
diff /tmp/qoi{,xx}/${i}
68+
done
69+
popd
70+
bin/test
3471
- name: run
3572
shell: bash
3673
run: bin/qoibench 1 images --noreference --nowarmup
37-
- name: test
38-
shell: bash
39-
run: bin/test

.github/workflows/windows.yml

+43-7
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ jobs:
1717
install: >-
1818
git
1919
curl
20+
unzip
21+
diffutils
2022
mingw-w64-ucrt-x86_64-make
2123
mingw-w64-ucrt-x86_64-clang
2224
- uses: actions/checkout@v4
@@ -29,17 +31,51 @@ jobs:
2931
- id: cached
3032
uses: andstor/file-existence-action@v3
3133
with:
32-
files: images
33-
- name: get benchmark suite
34+
files: "images, qoi_test_images"
35+
- name: get test/benchmark suite
3436
if: steps.cached.outputs.files_exists == 'false'
35-
shell: bash
36-
run: curl https://qoiformat.org/benchmark/qoi_benchmark_suite.tar | tar x
37+
shell: msys2 {0}
38+
run: |
39+
curl -O https://qoiformat.org/qoi_test_images.zip
40+
unzip qoi_test_images.zip
41+
rm qoi_test_images.zip
42+
curl https://qoiformat.org/benchmark/qoi_benchmark_suite.tar | tar x
43+
- name: build reference qoiconv
44+
shell: msys2 {0}
45+
run: |
46+
pushd .dependencies/qoi
47+
ln -s ../stb/stb_image.h .
48+
ln -s ../stb/stb_image_write.h .
49+
mingw32-make conv
50+
popd
51+
mv .dependencies/qoi/qoiconv.exe bin/qoiconv_orig.exe
3752
- name: build
3853
shell: msys2 {0}
3954
run: CXX=clang++ mingw32-make -j
55+
- name: test
56+
shell: msys2 {0}
57+
run: |
58+
pushd qoi_test_images
59+
mkdir -p /tmp/qoixx
60+
mkdir -p /tmp/qoi
61+
for i in ./*.qoi; do
62+
# test decode
63+
../bin/qoiconv ${i} /tmp/qoixx/${i%.*}.png
64+
../bin/qoiconv_orig ${i} /tmp/qoi/${i%.*}.png
65+
diff /tmp/qoi{,xx}/${i%.*}.png
66+
done
67+
rm -rf /tmp/qoixx/*.png
68+
rm -rf /tmp/qoi/*.png
69+
for i in ./*.png; do
70+
# test encode
71+
../bin/qoiconv ${i} /tmp/qoixx/${i%.*}.qoi
72+
../bin/qoiconv_orig /tmp/qoixx/${i%.*}.qoi /tmp/qoixx/${i}
73+
../bin/qoiconv_orig ${i} /tmp/qoi/${i%.*}.qoi
74+
../bin/qoiconv_orig /tmp/qoi/${i%.*}.qoi /tmp/qoi/${i}
75+
diff /tmp/qoi{,xx}/${i}
76+
done
77+
popd
78+
bin/test
4079
- name: run
4180
shell: msys2 {0}
4281
run: bin/qoibench 1 images --noreference --nowarmup
43-
- name: test
44-
shell: msys2 {0}
45-
run: bin/test

include/qoixx.hpp

+11-2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include<bit>
1212
#include<numeric>
1313
#include<array>
14+
#include<utility>
1415

1516
#ifndef QOIXX_NO_SIMD
1617
#if defined(__ARM_FEATURE_SVE)
@@ -1146,7 +1147,7 @@ class qoi{
11461147
static constexpr auto hash_diff_table = luma_hash_diff_table.data() + hash_table_offset;
11471148
)
11481149

1149-
const auto f = [&pixels, &p, &px_len, &size, &px, &index QOIXX_HPP_WITH_TABLES(, &hash)]{
1150+
const auto f = [&pixels, &p, &px_len, &size, &px, &index QOIXX_HPP_WITH_TABLES(, &hash)](bool first){
11501151
static constexpr std::uint32_t mask_tail_6 = 0b0011'1111u;
11511152
[[maybe_unused]] static constexpr std::uint32_t mask_tail_4 = 0b0000'1111u;
11521153
[[maybe_unused]] static constexpr std::uint32_t mask_tail_2 = 0b0000'0011u;
@@ -1187,6 +1188,13 @@ class qoi{
11871188
run = px_len;
11881189
px_len -= run;
11891190
QOIXX_HPP_DECODE_RUN(px, run)
1191+
if(first)[[unlikely]]{
1192+
QOIXX_HPP_WITH_TABLES(hash = (0*3+0*5+0*7+255*11) % index_size;)
1193+
if constexpr(std::is_same<rgba_t, qoi::rgba_t>::value)
1194+
index[QOIXX_HPP_WITH_TABLES(hash) QOIXX_HPP_WITHOUT_TABLES((0*3+0*5+0*7+255*11) % index_size)] = px;
1195+
else
1196+
efficient_memcpy<Channels>(index + QOIXX_HPP_WITH_TABLES(hash) QOIXX_HPP_WITHOUT_TABLES((0*3+0*5+0*7+255*11) % index_size), &px);
1197+
}
11901198
return;
11911199
}
11921200
if(b1 == chunk_tag::rgb){
@@ -1271,8 +1279,9 @@ class qoi{
12711279
push<Channels>(pixels, &px);
12721280
};
12731281

1282+
bool first = true;
12741283
while(px_len--)[[likely]]{
1275-
f();
1284+
f(std::exchange(first, false));
12761285
if(size < sizeof(padding))[[unlikely]]{
12771286
throw std::runtime_error("qoixx::qoi::decode: insufficient input data");
12781287
}

0 commit comments

Comments
 (0)