+ /* Fetch texels */
+ if (useBorderColor & (I0BIT | J0BIT)) {
+ COPY_CHAN4(t00, tObj->_BorderChan);
+ }
+ else {
+ img->FetchTexelc(img, i0, j0, array, t00);
+ }
+ if (useBorderColor & (I1BIT | J0BIT)) {
+ COPY_CHAN4(t10, tObj->_BorderChan);
+ }
+ else {
+ img->FetchTexelc(img, i1, j0, array, t10);
+ }
+ if (useBorderColor & (I0BIT | J1BIT)) {
+ COPY_CHAN4(t01, tObj->_BorderChan);
+ }
+ else {
+ img->FetchTexelc(img, i0, j1, array, t01);
+ }
+ if (useBorderColor & (I1BIT | J1BIT)) {
+ COPY_CHAN4(t11, tObj->_BorderChan);
+ }
+ else {
+ img->FetchTexelc(img, i1, j1, array, t11);
+ }
+
+ /* trilinear interpolation of samples */
+ lerp_rgba_2d(rgba, a, b, t00, t10, t01, t11);
+ }
+}
+
+
+static void
+sample_2d_array_nearest_mipmap_nearest(GLcontext *ctx,
+ const struct gl_texture_object *tObj,
+ GLuint n, const GLfloat texcoord[][4],
+ const GLfloat lambda[], GLchan rgba[][4])
+{
+ GLuint i;
+ for (i = 0; i < n; i++) {
+ GLint level = nearest_mipmap_level(tObj, lambda[i]);
+ sample_2d_array_nearest(ctx, tObj, tObj->Image[0][level], texcoord[i],
+ rgba[i]);
+ }
+}
+
+
+static void
+sample_2d_array_linear_mipmap_nearest(GLcontext *ctx,
+ const struct gl_texture_object *tObj,
+ GLuint n, const GLfloat texcoord[][4],
+ const GLfloat lambda[], GLchan rgba[][4])
+{
+ GLuint i;
+ ASSERT(lambda != NULL);
+ for (i = 0; i < n; i++) {
+ GLint level = nearest_mipmap_level(tObj, lambda[i]);
+ sample_2d_array_linear(ctx, tObj, tObj->Image[0][level],
+ texcoord[i], rgba[i]);
+ }
+}
+
+
+static void
+sample_2d_array_nearest_mipmap_linear(GLcontext *ctx,
+ const struct gl_texture_object *tObj,
+ GLuint n, const GLfloat texcoord[][4],
+ const GLfloat lambda[], GLchan rgba[][4])
+{
+ GLuint i;
+ ASSERT(lambda != NULL);
+ for (i = 0; i < n; i++) {
+ GLint level = linear_mipmap_level(tObj, lambda[i]);
+ if (level >= tObj->_MaxLevel) {
+ sample_2d_array_nearest(ctx, tObj, tObj->Image[0][tObj->_MaxLevel],
+ texcoord[i], rgba[i]);
+ }
+ else {
+ GLchan t0[4], t1[4]; /* texels */
+ const GLfloat f = FRAC(lambda[i]);
+ sample_2d_array_nearest(ctx, tObj, tObj->Image[0][level ],
+ texcoord[i], t0);
+ sample_2d_array_nearest(ctx, tObj, tObj->Image[0][level+1],
+ texcoord[i], t1);
+ lerp_rgba(rgba[i], f, t0, t1);
+ }
+ }
+}
+
+
+static void
+sample_2d_array_linear_mipmap_linear(GLcontext *ctx,
+ const struct gl_texture_object *tObj,
+ GLuint n, const GLfloat texcoord[][4],
+ const GLfloat lambda[], GLchan rgba[][4])
+{
+ GLuint i;
+ ASSERT(lambda != NULL);
+ for (i = 0; i < n; i++) {
+ GLint level = linear_mipmap_level(tObj, lambda[i]);
+ if (level >= tObj->_MaxLevel) {
+ sample_2d_array_linear(ctx, tObj, tObj->Image[0][tObj->_MaxLevel],
+ texcoord[i], rgba[i]);
+ }
+ else {
+ GLchan t0[4], t1[4]; /* texels */
+ const GLfloat f = FRAC(lambda[i]);
+ sample_2d_array_linear(ctx, tObj, tObj->Image[0][level ],
+ texcoord[i], t0);
+ sample_2d_array_linear(ctx, tObj, tObj->Image[0][level+1],
+ texcoord[i], t1);
+ lerp_rgba(rgba[i], f, t0, t1);
+ }
+ }
+}
+
+
+/** Sample 2D Array texture, nearest filtering for both min/magnification */
+static void
+sample_nearest_2d_array(GLcontext *ctx,
+ const struct gl_texture_object *tObj, GLuint n,
+ const GLfloat texcoords[][4], const GLfloat lambda[],
+ GLchan rgba[][4])
+{
+ GLuint i;
+ struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel];
+ (void) lambda;
+ for (i = 0; i < n; i++) {
+ sample_2d_array_nearest(ctx, tObj, image, texcoords[i], rgba[i]);
+ }
+}
+
+
+
+/** Sample 2D Array texture, linear filtering for both min/magnification */
+static void
+sample_linear_2d_array(GLcontext *ctx,
+ const struct gl_texture_object *tObj, GLuint n,
+ const GLfloat texcoords[][4],
+ const GLfloat lambda[], GLchan rgba[][4])
+{
+ GLuint i;
+ struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel];
+ (void) lambda;
+ for (i = 0; i < n; i++) {
+ sample_2d_array_linear(ctx, tObj, image, texcoords[i], rgba[i]);
+ }
+}
+
+
+/** Sample 2D Array texture, using lambda to choose between min/magnification */
+static void
+sample_lambda_2d_array(GLcontext *ctx,
+ const struct gl_texture_object *tObj, GLuint n,
+ const GLfloat texcoords[][4], const GLfloat lambda[],
+ GLchan rgba[][4])
+{
+ GLuint minStart, minEnd; /* texels with minification */
+ GLuint magStart, magEnd; /* texels with magnification */
+ GLuint i;
+
+ ASSERT(lambda != NULL);
+ compute_min_mag_ranges(tObj, n, lambda,
+ &minStart, &minEnd, &magStart, &magEnd);
+
+ if (minStart < minEnd) {
+ /* do the minified texels */
+ GLuint m = minEnd - minStart;
+ switch (tObj->MinFilter) {
+ case GL_NEAREST:
+ for (i = minStart; i < minEnd; i++)
+ sample_2d_array_nearest(ctx, tObj, tObj->Image[0][tObj->BaseLevel],
+ texcoords[i], rgba[i]);
+ break;
+ case GL_LINEAR:
+ for (i = minStart; i < minEnd; i++)
+ sample_2d_array_linear(ctx, tObj, tObj->Image[0][tObj->BaseLevel],
+ texcoords[i], rgba[i]);
+ break;
+ case GL_NEAREST_MIPMAP_NEAREST:
+ sample_2d_array_nearest_mipmap_nearest(ctx, tObj, m,
+ texcoords + minStart,
+ lambda + minStart,
+ rgba + minStart);
+ break;
+ case GL_LINEAR_MIPMAP_NEAREST:
+ sample_2d_array_linear_mipmap_nearest(ctx, tObj, m,
+ texcoords + minStart,
+ lambda + minStart,
+ rgba + minStart);
+ break;
+ case GL_NEAREST_MIPMAP_LINEAR:
+ sample_2d_array_nearest_mipmap_linear(ctx, tObj, m,
+ texcoords + minStart,
+ lambda + minStart,
+ rgba + minStart);
+ break;
+ case GL_LINEAR_MIPMAP_LINEAR:
+ sample_2d_array_linear_mipmap_linear(ctx, tObj, m,
+ texcoords + minStart,
+ lambda + minStart,
+ rgba + minStart);
+ break;
+ default:
+ _mesa_problem(ctx, "Bad min filter in sample_2d_array_texture");
+ return;
+ }
+ }
+
+ if (magStart < magEnd) {
+ /* do the magnified texels */
+ switch (tObj->MagFilter) {
+ case GL_NEAREST:
+ for (i = magStart; i < magEnd; i++)
+ sample_2d_array_nearest(ctx, tObj, tObj->Image[0][tObj->BaseLevel],
+ texcoords[i], rgba[i]);
+ break;
+ case GL_LINEAR:
+ for (i = magStart; i < magEnd; i++)
+ sample_2d_array_linear(ctx, tObj, tObj->Image[0][tObj->BaseLevel],
+ texcoords[i], rgba[i]);
+ break;
+ default:
+ _mesa_problem(ctx, "Bad mag filter in sample_2d_array_texture");
+ return;
+ }
+ }
+}
+
+
+
+
+/**********************************************************************/
+/* 1D Texture Array Sampling Functions */
+/**********************************************************************/
+
+/**
+ * Return the texture sample for coordinate (s,t,r) using GL_NEAREST filter.
+ */
+static void
+sample_1d_array_nearest(GLcontext *ctx,
+ const struct gl_texture_object *tObj,
+ const struct gl_texture_image *img,
+ const GLfloat texcoord[4],
+ GLchan rgba[4])
+{
+ const GLint width = img->Width2; /* without border, power of two */
+ const GLint height = img->Height;
+ GLint i;
+ GLint array;
+ (void) ctx;
+
+ i = nearest_texel_location(tObj->WrapS, img, width, texcoord[0]);
+ array = clamp_rect_coord_nearest(tObj->WrapT, texcoord[1], height);
+
+ if (i < 0 || i >= (GLint) img->Width ||
+ array < 0 || array >= (GLint) img->Height) {
+ /* Need this test for GL_CLAMP_TO_BORDER mode */
+ COPY_CHAN4(rgba, tObj->_BorderChan);
+ }
+ else {
+ img->FetchTexelc(img, i, array, 0, rgba);
+ }
+}
+
+
+/**
+ * Return the texture sample for coordinate (s,t,r) using GL_LINEAR filter.
+ */
+static void
+sample_1d_array_linear(GLcontext *ctx,
+ const struct gl_texture_object *tObj,
+ const struct gl_texture_image *img,
+ const GLfloat texcoord[4],
+ GLchan rgba[4])
+{
+ const GLint width = img->Width2;
+ const GLint height = img->Height;
+ GLint i0, i1;
+ GLint array;
+ GLbitfield useBorderColor = 0x0;
+ GLfloat a;
+ GLchan t0[4], t1[4];
+
+ linear_texel_locations(tObj->WrapS, img, width, texcoord[0], &i0, &i1, &a);
+ array = clamp_rect_coord_nearest(tObj->WrapT, texcoord[1], height);
+
+ if (img->Border) {
+ i0 += img->Border;
+ i1 += img->Border;
+ }
+ else {
+ /* check if sampling texture border color */
+ if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT;
+ if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT;
+ }
+
+ if (array < 0 || array >= height) useBorderColor |= K0BIT;
+
+ /* Fetch texels */
+ if (useBorderColor & (I0BIT | K0BIT)) {
+ COPY_CHAN4(t0, tObj->_BorderChan);
+ }
+ else {
+ img->FetchTexelc(img, i0, array, 0, t0);
+ }
+ if (useBorderColor & (I1BIT | K0BIT)) {
+ COPY_CHAN4(t1, tObj->_BorderChan);
+ }
+ else {
+ img->FetchTexelc(img, i1, array, 0, t1);
+ }
+
+ /* bilinear interpolation of samples */
+ lerp_rgba(rgba, a, t0, t1);
+}
+
+
+static void
+sample_1d_array_nearest_mipmap_nearest(GLcontext *ctx,
+ const struct gl_texture_object *tObj,
+ GLuint n, const GLfloat texcoord[][4],
+ const GLfloat lambda[], GLchan rgba[][4])
+{
+ GLuint i;
+ for (i = 0; i < n; i++) {
+ GLint level = nearest_mipmap_level(tObj, lambda[i]);
+ sample_1d_array_nearest(ctx, tObj, tObj->Image[0][level], texcoord[i],
+ rgba[i]);
+ }
+}
+
+
+static void
+sample_1d_array_linear_mipmap_nearest(GLcontext *ctx,
+ const struct gl_texture_object *tObj,
+ GLuint n, const GLfloat texcoord[][4],
+ const GLfloat lambda[], GLchan rgba[][4])
+{
+ GLuint i;
+ ASSERT(lambda != NULL);
+ for (i = 0; i < n; i++) {
+ GLint level = nearest_mipmap_level(tObj, lambda[i]);
+ sample_1d_array_linear(ctx, tObj, tObj->Image[0][level],
+ texcoord[i], rgba[i]);
+ }
+}
+
+
+static void
+sample_1d_array_nearest_mipmap_linear(GLcontext *ctx,
+ const struct gl_texture_object *tObj,
+ GLuint n, const GLfloat texcoord[][4],
+ const GLfloat lambda[], GLchan rgba[][4])
+{
+ GLuint i;
+ ASSERT(lambda != NULL);
+ for (i = 0; i < n; i++) {
+ GLint level = linear_mipmap_level(tObj, lambda[i]);
+ if (level >= tObj->_MaxLevel) {
+ sample_1d_array_nearest(ctx, tObj, tObj->Image[0][tObj->_MaxLevel],
+ texcoord[i], rgba[i]);
+ }
+ else {
+ GLchan t0[4], t1[4]; /* texels */
+ const GLfloat f = FRAC(lambda[i]);
+ sample_1d_array_nearest(ctx, tObj, tObj->Image[0][level ], texcoord[i], t0);
+ sample_1d_array_nearest(ctx, tObj, tObj->Image[0][level+1], texcoord[i], t1);
+ lerp_rgba(rgba[i], f, t0, t1);
+ }
+ }
+}
+
+
+static void
+sample_1d_array_linear_mipmap_linear(GLcontext *ctx,
+ const struct gl_texture_object *tObj,
+ GLuint n, const GLfloat texcoord[][4],
+ const GLfloat lambda[], GLchan rgba[][4])
+{
+ GLuint i;
+ ASSERT(lambda != NULL);
+ for (i = 0; i < n; i++) {
+ GLint level = linear_mipmap_level(tObj, lambda[i]);
+ if (level >= tObj->_MaxLevel) {
+ sample_1d_array_linear(ctx, tObj, tObj->Image[0][tObj->_MaxLevel],
+ texcoord[i], rgba[i]);
+ }
+ else {
+ GLchan t0[4], t1[4]; /* texels */
+ const GLfloat f = FRAC(lambda[i]);
+ sample_1d_array_linear(ctx, tObj, tObj->Image[0][level ], texcoord[i], t0);
+ sample_1d_array_linear(ctx, tObj, tObj->Image[0][level+1], texcoord[i], t1);
+ lerp_rgba(rgba[i], f, t0, t1);
+ }
+ }
+}
+
+
+/** Sample 1D Array texture, nearest filtering for both min/magnification */
+static void
+sample_nearest_1d_array(GLcontext *ctx,
+ const struct gl_texture_object *tObj, GLuint n,
+ const GLfloat texcoords[][4], const GLfloat lambda[],
+ GLchan rgba[][4])
+{
+ GLuint i;
+ struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel];
+ (void) lambda;
+ for (i = 0; i < n; i++) {
+ sample_1d_array_nearest(ctx, tObj, image, texcoords[i], rgba[i]);
+ }
+}
+
+
+/** Sample 1D Array texture, linear filtering for both min/magnification */
+static void
+sample_linear_1d_array(GLcontext *ctx,
+ const struct gl_texture_object *tObj, GLuint n,
+ const GLfloat texcoords[][4],
+ const GLfloat lambda[], GLchan rgba[][4])
+{
+ GLuint i;
+ struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel];
+ (void) lambda;
+ for (i = 0; i < n; i++) {
+ sample_1d_array_linear(ctx, tObj, image, texcoords[i], rgba[i]);
+ }
+}
+
+
+/** Sample 1D Array texture, using lambda to choose between min/magnification */
+static void
+sample_lambda_1d_array(GLcontext *ctx,
+ const struct gl_texture_object *tObj, GLuint n,
+ const GLfloat texcoords[][4], const GLfloat lambda[],
+ GLchan rgba[][4])
+{
+ GLuint minStart, minEnd; /* texels with minification */
+ GLuint magStart, magEnd; /* texels with magnification */
+ GLuint i;
+
+ ASSERT(lambda != NULL);
+ compute_min_mag_ranges(tObj, n, lambda,
+ &minStart, &minEnd, &magStart, &magEnd);
+
+ if (minStart < minEnd) {
+ /* do the minified texels */
+ GLuint m = minEnd - minStart;
+ switch (tObj->MinFilter) {
+ case GL_NEAREST:
+ for (i = minStart; i < minEnd; i++)
+ sample_1d_array_nearest(ctx, tObj, tObj->Image[0][tObj->BaseLevel],
+ texcoords[i], rgba[i]);
+ break;
+ case GL_LINEAR:
+ for (i = minStart; i < minEnd; i++)
+ sample_1d_array_linear(ctx, tObj, tObj->Image[0][tObj->BaseLevel],
+ texcoords[i], rgba[i]);
+ break;
+ case GL_NEAREST_MIPMAP_NEAREST:
+ sample_1d_array_nearest_mipmap_nearest(ctx, tObj, m, texcoords + minStart,
+ lambda + minStart, rgba + minStart);
+ break;
+ case GL_LINEAR_MIPMAP_NEAREST:
+ sample_1d_array_linear_mipmap_nearest(ctx, tObj, m,
+ texcoords + minStart,
+ lambda + minStart,
+ rgba + minStart);
+ break;
+ case GL_NEAREST_MIPMAP_LINEAR:
+ sample_1d_array_nearest_mipmap_linear(ctx, tObj, m, texcoords + minStart,
+ lambda + minStart, rgba + minStart);
+ break;
+ case GL_LINEAR_MIPMAP_LINEAR:
+ sample_1d_array_linear_mipmap_linear(ctx, tObj, m,
+ texcoords + minStart,
+ lambda + minStart,
+ rgba + minStart);
+ break;
+ default:
+ _mesa_problem(ctx, "Bad min filter in sample_1d_array_texture");
+ return;
+ }
+ }
+
+ if (magStart < magEnd) {
+ /* do the magnified texels */
+ switch (tObj->MagFilter) {
+ case GL_NEAREST:
+ for (i = magStart; i < magEnd; i++)
+ sample_1d_array_nearest(ctx, tObj, tObj->Image[0][tObj->BaseLevel],
+ texcoords[i], rgba[i]);
+ break;
+ case GL_LINEAR:
+ for (i = magStart; i < magEnd; i++)
+ sample_1d_array_linear(ctx, tObj, tObj->Image[0][tObj->BaseLevel],
+ texcoords[i], rgba[i]);
+ break;
+ default:
+ _mesa_problem(ctx, "Bad mag filter in sample_1d_array_texture");
+ return;
+ }
+ }
+}
+
+
+/**
+ * Sample a shadow/depth texture.
+ */
+static void
+sample_depth_texture( GLcontext *ctx,
+ const struct gl_texture_object *tObj, GLuint n,
+ const GLfloat texcoords[][4], const GLfloat lambda[],
+ GLchan texel[][4] )
+{
+ const GLint baseLevel = tObj->BaseLevel;
+ const struct gl_texture_image *img = tObj->Image[0][baseLevel];
+ const GLint width = img->Width;
+ const GLint height = img->Height;
+ const GLint depth = img->Depth;
+ const GLuint compare_coord = (tObj->Target == GL_TEXTURE_2D_ARRAY_EXT)
+ ? 3 : 2;
+ GLchan ambient;
+ GLenum function;
+ GLchan result;
+
+ (void) lambda;
+
+ ASSERT(img->TexFormat->BaseFormat == GL_DEPTH_COMPONENT ||
+ img->TexFormat->BaseFormat == GL_DEPTH_STENCIL_EXT);
+
+ ASSERT(tObj->Target == GL_TEXTURE_1D ||
+ tObj->Target == GL_TEXTURE_2D ||
+ tObj->Target == GL_TEXTURE_RECTANGLE_NV ||
+ tObj->Target == GL_TEXTURE_1D_ARRAY_EXT ||
+ tObj->Target == GL_TEXTURE_2D_ARRAY_EXT);
+
+ UNCLAMPED_FLOAT_TO_CHAN(ambient, tObj->ShadowAmbient);
+
+ /* XXXX if tObj->MinFilter != tObj->MagFilter, we're ignoring lambda */
+
+ function = tObj->_Function;
+ if (tObj->MagFilter == GL_NEAREST) {
+ GLuint i;
+ for (i = 0; i < n; i++) {
+ GLfloat depthSample;
+ GLint col, row, slice;
+
+ switch (tObj->Target) {
+ case GL_TEXTURE_RECTANGLE_ARB:
+ col = clamp_rect_coord_nearest(tObj->WrapS, texcoords[i][0], width);
+ row = clamp_rect_coord_nearest(tObj->WrapT, texcoords[i][1], height);
+ slice = 0;
+ break;
+
+ case GL_TEXTURE_1D:
+ col = nearest_texel_location(tObj->WrapS, img, width,
+ texcoords[i][0]);
+ row = 0;
+ slice = 0;
+ break;
+
+ case GL_TEXTURE_2D:
+ col = nearest_texel_location(tObj->WrapS, img, width,
+ texcoords[i][0]);
+ row = nearest_texel_location(tObj->WrapT, img, height,
+ texcoords[i][1]);
+ slice = 0;
+ break;
+
+ case GL_TEXTURE_1D_ARRAY_EXT:
+ col = nearest_texel_location(tObj->WrapS, img, width,
+ texcoords[i][0]);
+ row = clamp_rect_coord_nearest(tObj->WrapT, texcoords[i][1], height);
+ slice = 0;
+ break;
+
+ case GL_TEXTURE_2D_ARRAY_EXT:
+ col = nearest_texel_location(tObj->WrapS, img, width,
+ texcoords[i][0]);
+ row = nearest_texel_location(tObj->WrapT, img, height,
+ texcoords[i][1]);
+ slice = clamp_rect_coord_nearest(tObj->WrapR, texcoords[i][2], depth);
+ break;
+ }
+
+ if (col >= 0 && row >= 0 && col < width && row < height &&
+ slice >= 0 && slice < depth) {
+ img->FetchTexelf(img, col, row, slice, &depthSample);
+ }
+ else {
+ depthSample = tObj->BorderColor[0];
+ }
+
+ switch (function) {
+ case GL_LEQUAL:
+ result = (texcoords[i][compare_coord] <= depthSample) ? CHAN_MAX : ambient;
+ break;
+ case GL_GEQUAL:
+ result = (texcoords[i][compare_coord] >= depthSample) ? CHAN_MAX : ambient;