File: texture2d.ispc

package info (click to toggle)
embree 3.13.5%2Bdfsg-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 27,924 kB
  • sloc: cpp: 180,815; xml: 3,877; ansic: 2,957; python: 1,466; sh: 502; makefile: 229; csh: 42
file content (199 lines) | stat: -rw-r--r-- 6,812 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
// Copyright 2009-2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0

#include "texture2d.isph"


// Low-level texel accessors
//////////////////////////////////////////////////////////////////////////////

// TODO blocking

inline Vec4f getTexel_RGBA8(const uniform Texture2D *uniform self, const Vec2i i)
{
  assert(self);
  const uint32 c = ((const uniform uint32 *uniform)self->data)[i.y*self->size.x + i.x];
  const uint32 r = c         & 0xff;
  const uint32 g = (c >>  8) & 0xff;
  const uint32 b = (c >> 16) & 0xff;
  const uint32 a = c >> 24;
  return make_Vec4f((float)r, (float)g, (float)b, (float)a)*(1.f/255.f);
}

inline Vec4f getTexel_RGB8(const uniform Texture2D *uniform self, const Vec2i i)
{
  assert(self);
  const uniform uint8 *uniform texel = (const uniform uint8 *uniform)self->data;
  const uint32 texelOfs = 3*(i.y*self->size.x + i.x);
  const uint32 r = texel[texelOfs];
  const uint32 g = texel[texelOfs+1];
  const uint32 b = texel[texelOfs+2];
  return make_Vec4f(make_Vec3f((float)r, (float)g, (float)b)*(1.f/255.f), 1.f);
}

inline Vec4f getTexel_R8(const uniform Texture2D *uniform self, const Vec2i i)
{
  assert(self);
  const uint8 c = ((const uniform uint8 *uniform)self->data)[i.y*self->size.x + i.x];
  return make_Vec4f(c*(1.f/255.f), 0.0f, 0.0f, 1.f);
}

inline Vec4f getTexel_SRGBA(const uniform Texture2D *uniform self, const Vec2i i)
{
  return srgba_to_linear(getTexel_RGBA8(self, i));
}

inline Vec4f getTexel_SRGB(const uniform Texture2D *uniform self, const Vec2i i)
{
  return srgba_to_linear(getTexel_RGB8(self, i));
}

inline Vec4f getTexel_RGBA32F(const uniform Texture2D *uniform self, const Vec2i i)
{
  assert(self);
  return ((const uniform Vec4f *uniform)self->data)[i.y*self->size.x + i.x];
}

inline Vec4f getTexel_RGB32F(const uniform Texture2D *uniform self, const Vec2i i)
{
  assert(self);
  Vec3f v = ((const uniform Vec3f*uniform )self->data)[i.y*self->size.x + i.x];
  return make_Vec4f(v, 1.f);
}

inline Vec4f getTexel_R32F(const uniform Texture2D *uniform self, const Vec2i i)
{
  assert(self);
  float v = ((const uniform float*uniform)self->data)[i.y*self->size.x + i.x];
  return make_Vec4f(v, 0.f, 0.f, 1.f);
}


// Texture coordinate utilities
//////////////////////////////////////////////////////////////////////////////

inline Vec2i nearest_coords(const uniform Texture2D *uniform self, const Vec2f p)
{
  // repeat: get remainder within [0..1] parameter space
  Vec2f tc = frac(p);
  tc = max(tc, make_Vec2f(0.0f)); // filter out inf/NaN

  // scale by texture size
  tc = tc * self->sizef;

  // nearest
  return make_Vec2i(tc);
}

struct BilinCoords {
  Vec2i st0;
  Vec2i st1;
  Vec2f frac;
};

inline BilinCoords bilinear_coords(const uniform Texture2D *uniform self, const Vec2f p)
{
  BilinCoords coords;

  // repeat: get remainder within [0..1] parameter space
  // lower sample shifted by half a texel
  Vec2f tc = frac(p - self->halfTexel);
  tc = max(tc, make_Vec2f(0.0f)); // filter out inf/NaN

  // scale by texture size
  tc = tc * self->sizef;
  coords.frac = frac(tc);

  coords.st0 = make_Vec2i(tc);
  coords.st1 = coords.st0 + 1;
  // handle border cases
  if (coords.st1.x >= self->size.x)
    coords.st1.x = 0;
  if (coords.st1.y >= self->size.y)
    coords.st1.y = 0;

  return coords;
}

inline Vec4f bilerp(const Vec2f frac, const Vec4f c00, const Vec4f c01, const Vec4f c10, const Vec4f c11)
{
  return lerp(frac.y,
              lerp(frac.x, c00, c01),
              lerp(frac.x, c10, c11));
}


// Implementations of Texture2D_get for different formats and filter modi
//////////////////////////////////////////////////////////////////////////////

#define __define_tex_get(FMT)                                                \
                                                                             \
static Vec4f Texture2D_nearest_##FMT(const uniform Texture2D *uniform self,  \
    const Vec2f &p)                                                          \
{                                                                            \
  return getTexel_##FMT(self, nearest_coords(self, p));                      \
}                                                                            \
                                                                             \
static Vec4f Texture2D_bilinear_##FMT(const uniform Texture2D *uniform self, \
    const Vec2f &p)                                                          \
{                                                                            \
  BilinCoords cs = bilinear_coords(self, p);                                 \
                                                                             \
  const Vec4f c00 = getTexel_##FMT(self, make_Vec2i(cs.st0.x, cs.st0.y));    \
  const Vec4f c01 = getTexel_##FMT(self, make_Vec2i(cs.st1.x, cs.st0.y));    \
  const Vec4f c10 = getTexel_##FMT(self, make_Vec2i(cs.st0.x, cs.st1.y));    \
  const Vec4f c11 = getTexel_##FMT(self, make_Vec2i(cs.st1.x, cs.st1.y));    \
                                                                             \
  return bilerp(cs.frac, c00, c01, c10, c11);                                \
}

#define __define_tex_get_case(FMT) \
  case TEXTURE_##FMT: return filter_nearest ?  &Texture2D_nearest_##FMT : \
                                                   &Texture2D_bilinear_##FMT;

#define __foreach_fetcher(FCT) \
  FCT(RGBA8)                   \
  FCT(SRGBA)                   \
  FCT(RGBA32F)                 \
  FCT(RGB8)                    \
  FCT(SRGB)                    \
  FCT(RGB32F)                  \
  FCT(R8)                      \
  FCT(R32F)   

__foreach_fetcher(__define_tex_get)

static uniform Texture2D_get Texture2D_get_addr(const uniform uint32 type,
    const uniform bool filter_nearest)
{
  switch (type) {
    __foreach_fetcher(__define_tex_get_case)
  }
  return 0;
};

#undef __define_tex_get
#undef __define_tex_get_addr
#undef __foreach_fetcher


// Exports (called from C++)
//////////////////////////////////////////////////////////////////////////////

export void *uniform Texture2D_create(uniform Vec2i &size, void *uniform data,
    uniform uint32 type, uniform uint32 flags)
{
  uniform Texture2D *uniform self = uniform new uniform Texture2D;
  self->size      = size;

  // Due to float rounding frac(x) can be exactly 1.0f (e.g. for very small
  // negative x), although it should be strictly smaller than 1.0f. We handle
  // this case by having sizef slightly smaller than size, such that
  // frac(x)*sizef is always < size.
  self->sizef = make_Vec2f(nextafter((float)size.x, -1.0f), nextafter((float)size.y, -1.0f));
  self->halfTexel = make_Vec2f(0.5f/size.x, 0.5f/size.y);
  self->data = data;
  self->get = Texture2D_get_addr(type, flags & TEXTURE_FILTER_NEAREST);

  return self;
}