1 /* 2 * Copyright 2016 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "Test.h" 9 #include "SkHalf.h" 10 #include "SkRasterPipeline.h" 11 #include "../src/jumper/SkJumper.h" 12 13 DEF_TEST(SkRasterPipeline, r) { 14 // Build and run a simple pipeline to exercise SkRasterPipeline, 15 // drawing 50% transparent blue over opaque red in half-floats. 16 uint64_t red = 0x3c00000000003c00ull, 17 blue = 0x3800380000000000ull, 18 result; 19 20 SkJumper_MemoryCtx load_s_ctx = { &blue, 0 }, 21 load_d_ctx = { &red, 0 }, 22 store_ctx = { &result, 0 }; 23 24 SkRasterPipeline_<256> p; 25 p.append(SkRasterPipeline::load_f16, &load_s_ctx); 26 p.append(SkRasterPipeline::load_f16_dst, &load_d_ctx); 27 p.append(SkRasterPipeline::srcover); 28 p.append(SkRasterPipeline::store_f16, &store_ctx); 29 p.run(0,0,1,1); 30 31 // We should see half-intensity magenta. 32 REPORTER_ASSERT(r, ((result >> 0) & 0xffff) == 0x3800); 33 REPORTER_ASSERT(r, ((result >> 16) & 0xffff) == 0x0000); 34 REPORTER_ASSERT(r, ((result >> 32) & 0xffff) == 0x3800); 35 REPORTER_ASSERT(r, ((result >> 48) & 0xffff) == 0x3c00); 36 } 37 38 DEF_TEST(SkRasterPipeline_empty, r) { 39 // No asserts... just a test that this is safe to run. 40 SkRasterPipeline_<256> p; 41 p.run(0,0,20,1); 42 } 43 44 DEF_TEST(SkRasterPipeline_nonsense, r) { 45 // No asserts... just a test that this is safe to run and terminates. 46 // srcover() calls st->next(); this makes sure we've always got something there to call. 47 SkRasterPipeline_<256> p; 48 p.append(SkRasterPipeline::srcover); 49 p.run(0,0,20,1); 50 } 51 52 DEF_TEST(SkRasterPipeline_JIT, r) { 53 // This tests a couple odd corners that a JIT backend can stumble over. 54 55 uint32_t buf[72] = { 56 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 57 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 58 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 59 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 60 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 61 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62 }; 63 64 SkJumper_MemoryCtx src = { buf + 0, 0 }, 65 dst = { buf + 36, 0 }; 66 67 // Copy buf[x] to buf[x+36] for x in [15,35). 68 SkRasterPipeline_<256> p; 69 p.append(SkRasterPipeline:: load_8888, &src); 70 p.append(SkRasterPipeline::store_8888, &dst); 71 p.run(15,0, 20,1); 72 73 for (int i = 0; i < 36; i++) { 74 if (i < 15 || i == 35) { 75 REPORTER_ASSERT(r, buf[i+36] == 0); 76 } else { 77 REPORTER_ASSERT(r, buf[i+36] == (uint32_t)(i - 11)); 78 } 79 } 80 } 81 82 static uint16_t h(float f) { 83 // Remember, a float is 1-8-23 (sign-exponent-mantissa) with 127 exponent bias. 84 uint32_t sem; 85 memcpy(&sem, &f, sizeof(sem)); 86 uint32_t s = sem & 0x80000000, 87 em = sem ^ s; 88 89 // Convert to 1-5-10 half with 15 bias, flushing denorm halfs (including zero) to zero. 90 auto denorm = (int32_t)em < 0x38800000; // I32 comparison is often quicker, and always safe 91 // here. 92 return denorm ? SkTo<uint16_t>(0) 93 : SkTo<uint16_t>((s>>16) + (em>>13) - ((127-15)<<10)); 94 } 95 96 static uint16_t n(uint16_t x) { 97 return (x<<8) | (x>>8); 98 } 99 100 static float a(uint16_t x) { 101 return (1/65535.0f) * x; 102 } 103 104 DEF_TEST(SkRasterPipeline_tail, r) { 105 { 106 float data[][4] = { 107 {00, 01, 02, 03}, 108 {10, 11, 12, 13}, 109 {20, 21, 22, 23}, 110 {30, 31, 32, 33}, 111 }; 112 113 float buffer[4][4]; 114 115 SkJumper_MemoryCtx src = { &data[0][0], 0 }, 116 dst = { &buffer[0][0], 0 }; 117 118 for (unsigned i = 1; i <= 4; i++) { 119 memset(buffer, 0xff, sizeof(buffer)); 120 SkRasterPipeline_<256> p; 121 p.append(SkRasterPipeline::load_f32, &src); 122 p.append(SkRasterPipeline::store_f32, &dst); 123 p.run(0,0, i,1); 124 for (unsigned j = 0; j < i; j++) { 125 for (unsigned k = 0; k < 4; k++) { 126 if (buffer[j][k] != data[j][k]) { 127 ERRORF(r, "(%u, %u) - a: %g r: %g\n", j, k, data[j][k], buffer[j][k]); 128 } 129 } 130 } 131 for (int j = i; j < 4; j++) { 132 for (auto f : buffer[j]) { 133 REPORTER_ASSERT(r, SkScalarIsNaN(f)); 134 } 135 } 136 } 137 } 138 139 { 140 uint16_t data[][4] = { 141 {h(00), h(01), h(02), h(03)}, 142 {h(10), h(11), h(12), h(13)}, 143 {h(20), h(21), h(22), h(23)}, 144 {h(30), h(31), h(32), h(33)}, 145 }; 146 uint16_t buffer[4][4]; 147 SkJumper_MemoryCtx src = { &data[0][0], 0 }, 148 dst = { &buffer[0][0], 0 }; 149 150 for (unsigned i = 1; i <= 4; i++) { 151 memset(buffer, 0xff, sizeof(buffer)); 152 SkRasterPipeline_<256> p; 153 p.append(SkRasterPipeline::load_f16, &src); 154 p.append(SkRasterPipeline::store_f16, &dst); 155 p.run(0,0, i,1); 156 for (unsigned j = 0; j < i; j++) { 157 REPORTER_ASSERT(r, 158 !memcmp(&data[j][0], &buffer[j][0], sizeof(buffer[j]))); 159 } 160 for (int j = i; j < 4; j++) { 161 for (auto f : buffer[j]) { 162 REPORTER_ASSERT(r, f == 0xffff); 163 } 164 } 165 } 166 } 167 168 { 169 uint16_t data[][3] = { 170 {n(00), n(01), n(02)}, 171 {n(10), n(11), n(12)}, 172 {n(20), n(21), n(22)}, 173 {n(30), n(31), n(32)} 174 }; 175 176 float answer[][4] = { 177 {a(00), a(01), a(02), 1.0f}, 178 {a(10), a(11), a(12), 1.0f}, 179 {a(20), a(21), a(22), 1.0f}, 180 {a(30), a(31), a(32), 1.0f} 181 }; 182 183 float buffer[4][4]; 184 SkJumper_MemoryCtx src = { &data[0][0], 0 }, 185 dst = { &buffer[0][0], 0 }; 186 187 for (unsigned i = 1; i <= 4; i++) { 188 memset(buffer, 0xff, sizeof(buffer)); 189 SkRasterPipeline_<256> p; 190 p.append(SkRasterPipeline::load_rgb_u16_be, &src); 191 p.append(SkRasterPipeline::store_f32, &dst); 192 p.run(0,0, i,1); 193 for (unsigned j = 0; j < i; j++) { 194 for (unsigned k = 0; k < 4; k++) { 195 if (buffer[j][k] != answer[j][k]) { 196 ERRORF(r, "(%u, %u) - a: %g r: %g\n", j, k, answer[j][k], buffer[j][k]); 197 } 198 } 199 } 200 for (int j = i; j < 4; j++) { 201 for (auto f : buffer[j]) { 202 REPORTER_ASSERT(r, SkScalarIsNaN(f)); 203 } 204 } 205 } 206 } 207 } 208 209 DEF_TEST(SkRasterPipeline_lowp, r) { 210 uint32_t rgba[64]; 211 for (int i = 0; i < 64; i++) { 212 rgba[i] = (4*i+0) << 0 213 | (4*i+1) << 8 214 | (4*i+2) << 16 215 | (4*i+3) << 24; 216 } 217 218 SkJumper_MemoryCtx ptr = { rgba, 0 }; 219 220 SkRasterPipeline_<256> p; 221 p.append(SkRasterPipeline::load_bgra, &ptr); 222 p.append(SkRasterPipeline::store_8888, &ptr); 223 p.run(0,0,64,1); 224 225 for (int i = 0; i < 64; i++) { 226 uint32_t want = (4*i+0) << 16 227 | (4*i+1) << 8 228 | (4*i+2) << 0 229 | (4*i+3) << 24; 230 if (rgba[i] != want) { 231 ERRORF(r, "got %08x, want %08x\n", rgba[i], want); 232 } 233 } 234 } 235