#include "main/imports.h"
+#include "main/macros.h"
#include "main/mipmap.h"
#include "main/teximage.h"
#include "main/texformat.h"
#include "pipe/p_context.h"
#include "pipe/p_defines.h"
-#include "pipe/p_inlines.h"
+#include "util/u_inlines.h"
+#include "util/u_format.h"
#include "util/u_gen_mipmap.h"
+#include "util/u_math.h"
#include "cso_cache/cso_cache.h"
#include "cso_cache/cso_context.h"
+#include "st_debug.h"
#include "st_context.h"
-#include "st_draw.h"
#include "st_gen_mipmap.h"
-#include "st_program.h"
#include "st_texture.h"
#include "st_cb_texture.h"
#include "st_inlines.h"
static boolean
st_render_mipmap(struct st_context *st,
GLenum target,
- struct pipe_texture *pt,
+ struct st_texture_object *stObj,
uint baseLevel, uint lastLevel)
{
struct pipe_context *pipe = st->pipe;
struct pipe_screen *screen = pipe->screen;
+ struct pipe_sampler_view *psv = st_get_stobj_sampler_view(stObj);
const uint face = _mesa_tex_target_to_face(target);
assert(target != GL_TEXTURE_3D); /* not done yet */
/* check if we can render in the texture's format */
- if (!screen->is_format_supported(screen, pt->format, pt->target,
+ if (!screen->is_format_supported(screen, psv->format, psv->texture->target,
PIPE_TEXTURE_USAGE_RENDER_TARGET, 0)) {
return FALSE;
}
- util_gen_mipmap(st->gen_mipmap, pt, face, baseLevel, lastLevel,
+ util_gen_mipmap(st->gen_mipmap, psv, face, baseLevel, lastLevel,
PIPE_TEX_FILTER_LINEAR);
return TRUE;
struct gl_texture_object *texObj)
{
struct pipe_context *pipe = ctx->st->pipe;
- struct pipe_screen *screen = pipe->screen;
struct pipe_texture *pt = st_get_texobj_texture(texObj);
const uint baseLevel = texObj->BaseLevel;
const uint lastLevel = pt->last_level;
uint dstLevel;
GLenum datatype;
GLuint comps;
+
+ if (ST_DEBUG & DEBUG_FALLBACK)
+ debug_printf("%s: fallback processing\n", __FUNCTION__);
assert(target != GL_TEXTURE_3D); /* not done yet */
srcTrans = st_cond_flush_get_tex_transfer(st_context(ctx), pt, face,
srcLevel, zslice,
PIPE_TRANSFER_READ, 0, 0,
- pt->width[srcLevel],
- pt->height[srcLevel]);
+ u_minify(pt->width0, srcLevel),
+ u_minify(pt->height0, srcLevel));
dstTrans = st_cond_flush_get_tex_transfer(st_context(ctx), pt, face,
dstLevel, zslice,
PIPE_TRANSFER_WRITE, 0, 0,
- pt->width[dstLevel],
- pt->height[dstLevel]);
+ u_minify(pt->width0, dstLevel),
+ u_minify(pt->height0, dstLevel));
- srcData = (ubyte *) screen->transfer_map(screen, srcTrans);
- dstData = (ubyte *) screen->transfer_map(screen, dstTrans);
+ srcData = (ubyte *) pipe->transfer_map(pipe, srcTrans);
+ dstData = (ubyte *) pipe->transfer_map(pipe, dstTrans);
- srcStride = srcTrans->stride / srcTrans->block.size;
- dstStride = dstTrans->stride / dstTrans->block.size;
+ srcStride = srcTrans->stride / util_format_get_blocksize(srcTrans->texture->format);
+ dstStride = dstTrans->stride / util_format_get_blocksize(dstTrans->texture->format);
_mesa_generate_mipmap_level(target, datatype, comps,
- 0 /*border*/,
- pt->width[srcLevel], pt->height[srcLevel], pt->depth[srcLevel],
- srcData,
- srcStride, /* stride in texels */
- pt->width[dstLevel], pt->height[dstLevel], pt->depth[dstLevel],
- dstData,
- dstStride); /* stride in texels */
-
- screen->transfer_unmap(screen, srcTrans);
- screen->transfer_unmap(screen, dstTrans);
-
- screen->tex_transfer_destroy(srcTrans);
- screen->tex_transfer_destroy(dstTrans);
+ 0 /*border*/,
+ u_minify(pt->width0, srcLevel),
+ u_minify(pt->height0, srcLevel),
+ u_minify(pt->depth0, srcLevel),
+ srcData,
+ srcStride, /* stride in texels */
+ u_minify(pt->width0, dstLevel),
+ u_minify(pt->height0, dstLevel),
+ u_minify(pt->depth0, dstLevel),
+ dstData,
+ dstStride); /* stride in texels */
+
+ pipe->transfer_unmap(pipe, srcTrans);
+ pipe->transfer_unmap(pipe, dstTrans);
+
+ pipe->tex_transfer_destroy(pipe, srcTrans);
+ pipe->tex_transfer_destroy(pipe, dstTrans);
+ }
+}
+
+
+/**
+ * Compute the expected number of mipmap levels in the texture given
+ * the width/height/depth of the base image and the GL_TEXTURE_BASE_LEVEL/
+ * GL_TEXTURE_MAX_LEVEL settings. This will tell us how many mipmap
+ * level should be generated.
+ */
+static GLuint
+compute_num_levels(GLcontext *ctx,
+ struct gl_texture_object *texObj,
+ GLenum target)
+{
+ if (target == GL_TEXTURE_RECTANGLE_ARB) {
+ return 1;
+ }
+ else {
+ const GLuint maxLevels = texObj->MaxLevel - texObj->BaseLevel + 1;
+ const struct gl_texture_image *baseImage =
+ _mesa_get_tex_image(ctx, texObj, target, texObj->BaseLevel);
+ GLuint size, numLevels;
+
+ size = MAX2(baseImage->Width2, baseImage->Height2);
+ size = MAX2(size, baseImage->Depth2);
+
+ numLevels = 0;
+
+ while (size > 0) {
+ numLevels++;
+ size >>= 1;
+ }
+
+ numLevels = MIN2(numLevels, maxLevels);
+
+ return numLevels;
}
}
struct gl_texture_object *texObj)
{
struct st_context *st = ctx->st;
+ struct st_texture_object *stObj = st_texture_object(texObj);
struct pipe_texture *pt = st_get_texobj_texture(texObj);
const uint baseLevel = texObj->BaseLevel;
uint lastLevel;
if (!pt)
return;
- lastLevel = pt->last_level;
+ /* find expected last mipmap level */
+ lastLevel = compute_num_levels(ctx, texObj, target) - 1;
+
+ if (lastLevel == 0)
+ return;
+
+ if (pt->last_level < lastLevel) {
+ /* The current gallium texture doesn't have space for all the
+ * mipmap levels we need to generate. So allocate a new texture.
+ */
+ struct pipe_texture *oldTex = stObj->pt;
+ GLboolean needFlush;
+
+ /* create new texture with space for more levels */
+ stObj->pt = st_texture_create(st,
+ oldTex->target,
+ oldTex->format,
+ lastLevel,
+ oldTex->width0,
+ oldTex->height0,
+ oldTex->depth0,
+ oldTex->tex_usage);
+
+ /* The texture isn't in a "complete" state yet so set the expected
+ * lastLevel here, since it won't get done in st_finalize_texture().
+ */
+ stObj->lastLevel = lastLevel;
+
+ /* This will copy the old texture's base image into the new texture
+ * which we just allocated.
+ */
+ st_finalize_texture(ctx, st->pipe, texObj, &needFlush);
+
+ /* release the old tex (will likely be freed too) */
+ pipe_texture_reference(&oldTex, NULL);
+ pipe_sampler_view_reference(&stObj->sampler_view, NULL);
+
+ pt = stObj->pt;
+ }
- if (!st_render_mipmap(st, target, pt, baseLevel, lastLevel)) {
+ assert(lastLevel <= pt->last_level);
+
+ /* Recall that the Mesa BaseLevel image is stored in the gallium
+ * texture's level[0] position. So pass baseLevel=0 here.
+ */
+ if (!st_render_mipmap(st, target, stObj, 0, lastLevel)) {
fallback_generate_mipmap(ctx, target, texObj);
}
= _mesa_get_tex_image(ctx, texObj, target, srcLevel);
struct gl_texture_image *dstImage;
struct st_texture_image *stImage;
- uint dstWidth = pt->width[dstLevel];
- uint dstHeight = pt->height[dstLevel];
- uint dstDepth = pt->depth[dstLevel];
+ uint dstWidth = u_minify(pt->width0, dstLevel);
+ uint dstHeight = u_minify(pt->height0, dstLevel);
+ uint dstDepth = u_minify(pt->depth0, dstLevel);
uint border = srcImage->Border;
dstImage = _mesa_get_tex_image(ctx, texObj, target, dstLevel);
return;
}
- if (dstImage->ImageOffsets)
- _mesa_free(dstImage->ImageOffsets);
-
/* Free old image data */
if (dstImage->Data)
ctx->Driver.FreeTexImageData(ctx, dstImage);