#include "rs_core.rsh" #include "rs_structs.h" // 565 Conversion bits taken from SkBitmap #define SK_R16_BITS 5 #define SK_G16_BITS 6 #define SK_B16_BITS 5 #define SK_R16_SHIFT (SK_B16_BITS + SK_G16_BITS) #define SK_G16_SHIFT (SK_B16_BITS) #define SK_B16_SHIFT 0 #define SK_R16_MASK ((1 << SK_R16_BITS) - 1) #define SK_G16_MASK ((1 << SK_G16_BITS) - 1) #define SK_B16_MASK ((1 << SK_B16_BITS) - 1) #define SkGetPackedR16(color) (((unsigned)(color) >> SK_R16_SHIFT) & SK_R16_MASK) #define SkGetPackedG16(color) (((unsigned)(color) >> SK_G16_SHIFT) & SK_G16_MASK) #define SkGetPackedB16(color) (((unsigned)(color) >> SK_B16_SHIFT) & SK_B16_MASK) static inline unsigned SkR16ToR32(unsigned r) { return (r << (8 - SK_R16_BITS)) | (r >> (2 * SK_R16_BITS - 8)); } static inline unsigned SkG16ToG32(unsigned g) { return (g << (8 - SK_G16_BITS)) | (g >> (2 * SK_G16_BITS - 8)); } static inline unsigned SkB16ToB32(unsigned b) { return (b << (8 - SK_B16_BITS)) | (b >> (2 * SK_B16_BITS - 8)); } #define SkPacked16ToR32(c) SkR16ToR32(SkGetPackedR16(c)) #define SkPacked16ToG32(c) SkG16ToG32(SkGetPackedG16(c)) #define SkPacked16ToB32(c) SkB16ToB32(SkGetPackedB16(c)) static float3 getFrom565(uint16_t color) { float3 result; result.x = (float)SkPacked16ToR32(color); result.y = (float)SkPacked16ToG32(color); result.z = (float)SkPacked16ToB32(color); return result; } /** * Allocation sampling */ static inline float __attribute__((overloadable)) getElementAt1(const uint8_t *p, int32_t x) { float r = p[x]; return r; } static inline float2 __attribute__((overloadable)) getElementAt2(const uint8_t *p, int32_t x) { x *= 2; float2 r = {p[x], p[x+1]}; return r; } static inline float3 __attribute__((overloadable)) getElementAt3(const uint8_t *p, int32_t x) { x *= 4; float3 r = {p[x], p[x+1], p[x+2]}; return r; } static inline float4 __attribute__((overloadable)) getElementAt4(const uint8_t *p, int32_t x) { x *= 4; const uchar4 *p2 = (const uchar4 *)&p[x]; return convert_float4(p2[0]); } static inline float3 __attribute__((overloadable)) getElementAt565(const uint8_t *p, int32_t x) { x *= 2; float3 r = getFrom565(((const uint16_t *)p)[0]); return r; } static inline float __attribute__((overloadable)) getElementAt1(const uint8_t *p, size_t stride, int32_t x, int32_t y) { p += y * stride; float r = p[x]; return r; } static inline float2 __attribute__((overloadable)) getElementAt2(const uint8_t *p, size_t stride, int32_t x, int32_t y) { p += y * stride; x *= 2; float2 r = {p[x], p[x+1]}; return r; } static inline float3 __attribute__((overloadable)) getElementAt3(const uint8_t *p, size_t stride, int32_t x, int32_t y) { p += y * stride; x *= 4; float3 r = {p[x], p[x+1], p[x+2]}; return r; } static inline float4 __attribute__((overloadable)) getElementAt4(const uint8_t *p, size_t stride, int32_t x, int32_t y) { p += y * stride; x *= 4; float4 r = {p[x], p[x+1], p[x+2], p[x+3]}; return r; } static inline float3 __attribute__((overloadable)) getElementAt565(const uint8_t *p, size_t stride, int32_t x, int32_t y) { p += y * stride; x *= 2; float3 r = getFrom565(((const uint16_t *)p)[0]); return r; } static float4 __attribute__((overloadable)) getSample_A(const uint8_t *p, int32_t iPixel, int32_t next, float w0, float w1) { float p0 = getElementAt1(p, iPixel); float p1 = getElementAt1(p, next); float r = p0 * w0 + p1 * w1; r *= (1.f / 255.f); float4 ret = {0.f, 0.f, 0.f, r}; return ret; } static float4 __attribute__((overloadable)) getSample_L(const uint8_t *p, int32_t iPixel, int32_t next, float w0, float w1) { float p0 = getElementAt1(p, iPixel); float p1 = getElementAt1(p, next); float r = p0 * w0 + p1 * w1; r *= (1.f / 255.f); float4 ret = {r, r, r, 1.f}; return ret; } static float4 __attribute__((overloadable)) getSample_LA(const uint8_t *p, int32_t iPixel, int32_t next, float w0, float w1) { float2 p0 = getElementAt2(p, iPixel); float2 p1 = getElementAt2(p, next); float2 r = p0 * w0 + p1 * w1; r *= (1.f / 255.f); float4 ret = {r.x, r.x, r.x, r.y}; return ret; } static float4 __attribute__((overloadable)) getSample_RGB(const uint8_t *p, int32_t iPixel, int32_t next, float w0, float w1) { float3 p0 = getElementAt3(p, iPixel); float3 p1 = getElementAt3(p, next); float3 r = p0 * w0 + p1 * w1; r *= (1.f / 255.f); float4 ret = {r.x, r.x, r.z, 1.f}; return ret; } static float4 __attribute__((overloadable)) getSample_565(const uint8_t *p, int32_t iPixel, int32_t next, float w0, float w1) { float3 p0 = getElementAt565(p, iPixel); float3 p1 = getElementAt565(p, next); float3 r = p0 * w0 + p1 * w1; r *= (1.f / 255.f); float4 ret = {r.x, r.x, r.z, 1.f}; return ret; } static float4 __attribute__((overloadable)) getSample_RGBA(const uint8_t *p, int32_t iPixel, int32_t next, float w0, float w1) { float4 p0 = getElementAt4(p, iPixel); float4 p1 = getElementAt4(p, next); float4 r = p0 * w0 + p1 * w1; r *= (1.f / 255.f); return r; } static float4 __attribute__((overloadable)) getSample_A(const uint8_t *p, size_t stride, int locX, int locY, int nextX, int nextY, float w0, float w1, float w2, float w3) { float p0 = getElementAt1(p, stride, locX, locY); float p1 = getElementAt1(p, stride, nextX, locY); float p2 = getElementAt1(p, stride, locX, nextY); float p3 = getElementAt1(p, stride, nextX, nextY); float r = p0 * w0 + p1 * w1 + p2 * w2 + p3 * w3; r *= (1.f / 255.f); float4 ret = {0.f, 0.f, 0.f, r}; return ret; } static float4 __attribute__((overloadable)) getSample_L(const uint8_t *p, size_t stride, int locX, int locY, int nextX, int nextY, float w0, float w1, float w2, float w3) { float p0 = getElementAt1(p, stride, locX, locY); float p1 = getElementAt1(p, stride, nextX, locY); float p2 = getElementAt1(p, stride, locX, nextY); float p3 = getElementAt1(p, stride, nextX, nextY); float r = p0 * w0 + p1 * w1 + p2 * w2 + p3 * w3; r *= (1.f / 255.f); float4 ret = {r, r, r, 1.f}; return ret; } static float4 __attribute__((overloadable)) getSample_LA(const uint8_t *p, size_t stride, int locX, int locY, int nextX, int nextY, float w0, float w1, float w2, float w3) { float2 p0 = getElementAt2(p, stride, locX, locY); float2 p1 = getElementAt2(p, stride, nextX, locY); float2 p2 = getElementAt2(p, stride, locX, nextY); float2 p3 = getElementAt2(p, stride, nextX, nextY); float2 r = p0 * w0 + p1 * w1 + p2 * w2 + p3 * w3; r *= (1.f / 255.f); float4 ret = {r.x, r.x, r.x, r.y}; return ret; } static float4 __attribute__((overloadable)) getSample_RGB(const uint8_t *p, size_t stride, int locX, int locY, int nextX, int nextY, float w0, float w1, float w2, float w3) { float4 p0 = getElementAt4(p, stride, locX, locY); float4 p1 = getElementAt4(p, stride, nextX, locY); float4 p2 = getElementAt4(p, stride, locX, nextY); float4 p3 = getElementAt4(p, stride, nextX, nextY); float4 r = p0 * w0 + p1 * w1 + p2 * w2 + p3 * w3; r *= (1.f / 255.f); float4 ret = {r.x, r.y, r.z, 1.f}; return ret; } static float4 __attribute__((overloadable)) getSample_RGBA(const uint8_t *p, size_t stride, int locX, int locY, int nextX, int nextY, float w0, float w1, float w2, float w3) { float4 p0 = getElementAt4(p, stride, locX, locY); float4 p1 = getElementAt4(p, stride, nextX, locY); float4 p2 = getElementAt4(p, stride, locX, nextY); float4 p3 = getElementAt4(p, stride, nextX, nextY); float4 r = p0 * w0 + p1 * w1 + p2 * w2 + p3 * w3; r *= (1.f / 255.f); return r; } static float4 __attribute__((overloadable)) getSample_565(const uint8_t *p, size_t stride, int locX, int locY, int nextX, int nextY, float w0, float w1, float w2, float w3) { float3 p0 = getElementAt565(p, stride, locX, locY); float3 p1 = getElementAt565(p, stride, nextX, locY); float3 p2 = getElementAt565(p, stride, locX, nextY); float3 p3 = getElementAt565(p, stride, nextX, nextY); float3 r = p0 * w0 + p1 * w1 + p2 * w2 + p3 * w3; r *= (1.f / 255.f); float4 ret; ret.rgb = r; ret.w = 1.f; return ret; } static float4 __attribute__((overloadable)) getBilinearSample1D(const Allocation_t *alloc, float2 weights, uint32_t iPixel, uint32_t next, rs_data_kind dk, rs_data_type dt, uint32_t lod) { const uint8_t *p = (const uint8_t *)alloc->mHal.drvState.lod[lod].mallocPtr; switch(dk) { case RS_KIND_PIXEL_RGBA: return getSample_RGBA(p, iPixel, next, weights.x, weights.y); case RS_KIND_PIXEL_A: return getSample_A(p, iPixel, next, weights.x, weights.y); case RS_KIND_PIXEL_RGB: if (dt == RS_TYPE_UNSIGNED_5_6_5) { return getSample_565(p, iPixel, next, weights.x, weights.y); } return getSample_RGB(p, iPixel, next, weights.x, weights.y); case RS_KIND_PIXEL_L: return getSample_L(p, iPixel, next, weights.x, weights.y); case RS_KIND_PIXEL_LA: return getSample_LA(p, iPixel, next, weights.x, weights.y); default: //__builtin_unreachable(); break; } //__builtin_unreachable(); return 0.f; } static uint32_t wrapI(rs_sampler_value wrap, int32_t coord, int32_t size) { if (wrap == RS_SAMPLER_WRAP) { coord = coord % size; if (coord < 0) { coord += size; } } if (wrap == RS_SAMPLER_MIRRORED_REPEAT) { coord = coord % (size * 2); if (coord < 0) { coord = (size * 2) + coord; } if (coord >= size) { coord = (size * 2 - 1) - coord; } } return (uint32_t)max(0, min(coord, size - 1)); } static float4 __attribute__((overloadable)) getBilinearSample2D(const Allocation_t *alloc, float w0, float w1, float w2, float w3, int lx, int ly, int nx, int ny, rs_data_kind dk, rs_data_type dt, uint32_t lod) { const uint8_t *p = (const uint8_t *)alloc->mHal.drvState.lod[lod].mallocPtr; size_t stride = alloc->mHal.drvState.lod[lod].stride; switch(dk) { case RS_KIND_PIXEL_RGBA: return getSample_RGBA(p, stride, lx, ly, nx, ny, w0, w1, w2, w3); case RS_KIND_PIXEL_A: return getSample_A(p, stride, lx, ly, nx, ny, w0, w1, w2, w3); case RS_KIND_PIXEL_LA: return getSample_LA(p, stride, lx, ly, nx, ny, w0, w1, w2, w3); case RS_KIND_PIXEL_RGB: if (dt == RS_TYPE_UNSIGNED_5_6_5) { return getSample_565(p, stride, lx, ly, nx, ny, w0, w1, w2, w3); } return getSample_RGB(p, stride, lx, ly, nx, ny, w0, w1, w2, w3); case RS_KIND_PIXEL_L: return getSample_L(p, stride, lx, ly, nx, ny, w0, w1, w2, w3); default: break; } return 0.f; } static float4 __attribute__((overloadable)) getNearestSample(const Allocation_t *alloc, uint32_t iPixel, rs_data_kind dk, rs_data_type dt, uint32_t lod) { const uint8_t *p = (const uint8_t *)alloc->mHal.drvState.lod[lod].mallocPtr; float4 result = {0.f, 0.f, 0.f, 255.f}; switch(dk) { case RS_KIND_PIXEL_RGBA: result = getElementAt4(p, iPixel); break; case RS_KIND_PIXEL_A: result.w = getElementAt1(p, iPixel); break; case RS_KIND_PIXEL_LA: result.zw = getElementAt2(p, iPixel); result.xy = result.z; break; case RS_KIND_PIXEL_RGB: if (dt == RS_TYPE_UNSIGNED_5_6_5) { result.xyz = getElementAt565(p, iPixel); } else { result.xyz = getElementAt3(p, iPixel); } break; case RS_KIND_PIXEL_L: result.xyz = getElementAt1(p, iPixel); default: //__builtin_unreachable(); break; } return result * 0.003921569f; } static float4 __attribute__((overloadable)) getNearestSample(const Allocation_t *alloc, uint2 iPixel, rs_data_kind dk, rs_data_type dt, uint32_t lod) { const uint8_t *p = (const uint8_t *)alloc->mHal.drvState.lod[lod].mallocPtr; size_t stride = alloc->mHal.drvState.lod[lod].stride; float4 result = {0.f, 0.f, 0.f, 255.f}; switch(dk) { case RS_KIND_PIXEL_RGBA: result = getElementAt4(p, stride, iPixel.x, iPixel.y); break; case RS_KIND_PIXEL_A: result.w = getElementAt1(p, stride, iPixel.x, iPixel.y); break; case RS_KIND_PIXEL_LA: result.zw = getElementAt2(p, stride, iPixel.x, iPixel.y); result.xy = result.z; break; case RS_KIND_PIXEL_RGB: if (dt == RS_TYPE_UNSIGNED_5_6_5) { result.xyz = getElementAt565(p, stride, iPixel.x, iPixel.y); } else { result.xyz = getElementAt3(p, stride, iPixel.x, iPixel.y); } break; default: //__builtin_unreachable(); break; } return result * 0.003921569f; } static float4 __attribute__((overloadable)) sample_LOD_LinearPixel(const Allocation_t *alloc, rs_data_kind dk, rs_data_type dt, rs_sampler_value wrapS, float uv, uint32_t lod) { int32_t sourceW = alloc->mHal.drvState.lod[lod].dimX; float pixelUV = uv * (float)(sourceW); int32_t iPixel = floor(pixelUV); float frac = pixelUV - (float)iPixel; if (frac < 0.5f) { iPixel -= 1; frac += 0.5f; } else { frac -= 0.5f; } float oneMinusFrac = 1.0f - frac; float2 weights; weights.x = oneMinusFrac; weights.y = frac; uint32_t next = wrapI(wrapS, iPixel + 1, sourceW); uint32_t location = wrapI(wrapS, iPixel, sourceW); return getBilinearSample1D(alloc, weights, location, next, dk, dt, lod); } static float4 __attribute__((overloadable)) sample_LOD_NearestPixel(const Allocation_t *alloc, rs_data_kind dk, rs_data_type dt, rs_sampler_value wrapS, float uv, uint32_t lod) { int32_t sourceW = alloc->mHal.drvState.lod[lod].dimX; int32_t iPixel = floor(uv * (float)(sourceW)); uint32_t location = wrapI(wrapS, iPixel, sourceW); return getNearestSample(alloc, location, dk, dt, lod); } static float4 __attribute__((overloadable)) sample_LOD_LinearPixel(const Allocation_t *alloc, rs_data_kind dk, rs_data_type dt, rs_sampler_value wrapS, rs_sampler_value wrapT, float2 uv, uint32_t lod) { int sourceW = alloc->mHal.drvState.lod[lod].dimX; int sourceH = alloc->mHal.drvState.lod[lod].dimY; float pixelU = uv.x * sourceW; float pixelV = uv.y * sourceH; int iPixelU = floor(pixelU); int iPixelV = floor(pixelV); float fracU = pixelU - iPixelU; float fracV = pixelV - iPixelV; if (fracU < 0.5f) { iPixelU -= 1; fracU += 0.5f; } else { fracU -= 0.5f; } if (fracV < 0.5f) { iPixelV -= 1; fracV += 0.5f; } else { fracV -= 0.5f; } float oneMinusFracU = 1.0f - fracU; float oneMinusFracV = 1.0f - fracV; float w0 = oneMinusFracU * oneMinusFracV; float w1 = fracU * oneMinusFracV; float w2 = oneMinusFracU * fracV; float w3 = fracU * fracV; int nx = wrapI(wrapS, iPixelU + 1, sourceW); int ny = wrapI(wrapT, iPixelV + 1, sourceH); int lx = wrapI(wrapS, iPixelU, sourceW); int ly = wrapI(wrapT, iPixelV, sourceH); return getBilinearSample2D(alloc, w0, w1, w2, w3, lx, ly, nx, ny, dk, dt, lod); } static float4 __attribute__((overloadable)) sample_LOD_NearestPixel(const Allocation_t *alloc, rs_data_kind dk, rs_data_type dt, rs_sampler_value wrapS, rs_sampler_value wrapT, float2 uv, uint32_t lod) { int sourceW = alloc->mHal.drvState.lod[lod].dimX; int sourceH = alloc->mHal.drvState.lod[lod].dimY; float2 dimF; dimF.x = (float)(sourceW); dimF.y = (float)(sourceH); int2 iPixel = convert_int2(floor(uv * dimF)); uint2 location; location.x = wrapI(wrapS, iPixel.x, sourceW); location.y = wrapI(wrapT, iPixel.y, sourceH); return getNearestSample(alloc, location, dk, dt, lod); } extern float4 __attribute__((overloadable)) rsSample(rs_allocation a, rs_sampler s, float uv, float lod) { const Allocation_t *alloc = (const Allocation_t *)a.p; const Sampler_t *prog = (Sampler_t *)s.p; const Type_t *type = (Type_t *)alloc->mHal.state.type; const Element_t *elem = type->mHal.state.element; rs_data_kind dk = elem->mHal.state.dataKind; rs_data_type dt = elem->mHal.state.dataType; rs_sampler_value sampleMin = prog->mHal.state.minFilter; rs_sampler_value sampleMag = prog->mHal.state.magFilter; rs_sampler_value wrapS = prog->mHal.state.wrapS; if (!(alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE)) { return 0.f; } if (lod <= 0.0f) { if (sampleMag == RS_SAMPLER_NEAREST) { return sample_LOD_NearestPixel(alloc, dk, dt, wrapS, uv, 0); } return sample_LOD_LinearPixel(alloc, dk, dt, wrapS, uv, 0); } if (sampleMin == RS_SAMPLER_LINEAR_MIP_NEAREST) { uint32_t maxLOD = type->mHal.state.lodCount - 1; lod = min(lod, (float)maxLOD); uint32_t nearestLOD = (uint32_t)round(lod); return sample_LOD_LinearPixel(alloc, dk, dt, wrapS, uv, nearestLOD); } if (sampleMin == RS_SAMPLER_LINEAR_MIP_LINEAR) { uint32_t lod0 = (uint32_t)floor(lod); uint32_t lod1 = (uint32_t)ceil(lod); uint32_t maxLOD = type->mHal.state.lodCount - 1; lod0 = min(lod0, maxLOD); lod1 = min(lod1, maxLOD); float4 sample0 = sample_LOD_LinearPixel(alloc, dk, dt, wrapS, uv, lod0); float4 sample1 = sample_LOD_LinearPixel(alloc, dk, dt, wrapS, uv, lod1); float frac = lod - (float)lod0; return sample0 * (1.0f - frac) + sample1 * frac; } return sample_LOD_NearestPixel(alloc, dk, dt, wrapS, uv, 0); } extern float4 __attribute__((overloadable)) rsSample(rs_allocation a, rs_sampler s, float location) { return rsSample(a, s, location, 0); } extern float4 __attribute__((overloadable)) rsSample(rs_allocation a, rs_sampler s, float2 uv, float lod) { const Allocation_t *alloc = (const Allocation_t *)a.p; const Sampler_t *prog = (Sampler_t *)s.p; const Type_t *type = (Type_t *)alloc->mHal.state.type; const Element_t *elem = type->mHal.state.element; rs_data_kind dk = elem->mHal.state.dataKind; rs_data_type dt = elem->mHal.state.dataType; rs_sampler_value sampleMin = prog->mHal.state.minFilter; rs_sampler_value sampleMag = prog->mHal.state.magFilter; rs_sampler_value wrapS = prog->mHal.state.wrapS; rs_sampler_value wrapT = prog->mHal.state.wrapT; if (!(alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE)) { return 0.f; } if (lod <= 0.0f) { if (sampleMag == RS_SAMPLER_NEAREST) { return sample_LOD_NearestPixel(alloc, dk, dt, wrapS, wrapT, uv, 0); } return sample_LOD_LinearPixel(alloc, dk, dt, wrapS, wrapT, uv, 0); } if (sampleMin == RS_SAMPLER_LINEAR_MIP_NEAREST) { uint32_t maxLOD = type->mHal.state.lodCount - 1; lod = min(lod, (float)maxLOD); uint32_t nearestLOD = (uint32_t)round(lod); return sample_LOD_LinearPixel(alloc, dk, dt, wrapS, wrapT, uv, nearestLOD); } if (sampleMin == RS_SAMPLER_LINEAR_MIP_LINEAR) { uint32_t lod0 = (uint32_t)floor(lod); uint32_t lod1 = (uint32_t)ceil(lod); uint32_t maxLOD = type->mHal.state.lodCount - 1; lod0 = min(lod0, maxLOD); lod1 = min(lod1, maxLOD); float4 sample0 = sample_LOD_LinearPixel(alloc, dk, dt, wrapS, wrapT, uv, lod0); float4 sample1 = sample_LOD_LinearPixel(alloc, dk, dt, wrapS, wrapT, uv, lod1); float frac = lod - (float)lod0; return sample0 * (1.0f - frac) + sample1 * frac; } return sample_LOD_NearestPixel(alloc, dk, dt, wrapS, wrapT, uv, 0); } extern float4 __attribute__((overloadable)) rsSample(rs_allocation a, rs_sampler s, float2 uv) { const Allocation_t *alloc = (const Allocation_t *)a.p; const Sampler_t *prog = (Sampler_t *)s.p; const Type_t *type = (Type_t *)alloc->mHal.state.type; const Element_t *elem = type->mHal.state.element; rs_data_kind dk = elem->mHal.state.dataKind; rs_data_type dt = elem->mHal.state.dataType; rs_sampler_value wrapS = prog->mHal.state.wrapS; rs_sampler_value wrapT = prog->mHal.state.wrapT; if (!(alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE)) { return 0.f; } if (prog->mHal.state.magFilter == RS_SAMPLER_NEAREST) { return sample_LOD_NearestPixel(alloc, dk, dt, wrapS, wrapT, uv, 0); } return sample_LOD_LinearPixel(alloc, dk, dt, wrapS, wrapT, uv, 0); }