blob: 1b3aa89c051a45164405a9e296d335eb87747b21 [file] [log] [blame]
#include "mtypes.h"
#include "macros.h"
#include "intel_context.h"
#include "intel_batchbuffer.h"
#include "intel_mipmap_tree.h"
#include "intel_tex.h"
#define FILE_DEBUG_FLAG DEBUG_TEXTURE
/**
* Compute which mipmap levels that really need to be sent to the hardware.
* This depends on the base image size, GL_TEXTURE_MIN_LOD,
* GL_TEXTURE_MAX_LOD, GL_TEXTURE_BASE_LEVEL, and GL_TEXTURE_MAX_LEVEL.
*/
static void
intel_calculate_first_last_level(struct intel_texture_object *intelObj)
{
struct gl_texture_object *tObj = &intelObj->base;
const struct gl_texture_image *const baseImage =
tObj->Image[0][tObj->BaseLevel];
/* These must be signed values. MinLod and MaxLod can be negative numbers,
* and having firstLevel and lastLevel as signed prevents the need for
* extra sign checks.
*/
int firstLevel;
int lastLevel;
/* Yes, this looks overly complicated, but it's all needed.
*/
switch (tObj->Target) {
case GL_TEXTURE_1D:
case GL_TEXTURE_2D:
case GL_TEXTURE_3D:
case GL_TEXTURE_CUBE_MAP:
if (tObj->MinFilter == GL_NEAREST || tObj->MinFilter == GL_LINEAR) {
/* GL_NEAREST and GL_LINEAR only care about GL_TEXTURE_BASE_LEVEL.
*/
firstLevel = lastLevel = tObj->BaseLevel;
}
else {
#ifdef I915
firstLevel = tObj->BaseLevel + (GLint) (tObj->MinLod + 0.5);
firstLevel = MAX2(firstLevel, tObj->BaseLevel);
firstLevel = MIN2(firstLevel, tObj->BaseLevel + baseImage->MaxLog2);
lastLevel = tObj->BaseLevel + (GLint) (tObj->MaxLod + 0.5);
lastLevel = MAX2(lastLevel, tObj->BaseLevel);
lastLevel = MIN2(lastLevel, tObj->BaseLevel + baseImage->MaxLog2);
lastLevel = MIN2(lastLevel, tObj->MaxLevel);
lastLevel = MAX2(firstLevel, lastLevel); /* need at least one level */
#else
/* Currently not taking min/max lod into account here, those
* values are programmed as sampler state elsewhere and we
* upload the same mipmap levels regardless. Not sure if
* this makes sense as it means it isn't possible for the app
* to use min/max lod to reduce texture memory pressure:
*/
firstLevel = tObj->BaseLevel;
lastLevel = MIN2(tObj->BaseLevel + baseImage->MaxLog2,
tObj->MaxLevel);
lastLevel = MAX2(firstLevel, lastLevel); /* need at least one level */
#endif
}
break;
case GL_TEXTURE_RECTANGLE_NV:
case GL_TEXTURE_4D_SGIS:
firstLevel = lastLevel = 0;
break;
default:
return;
}
/* save these values */
intelObj->firstLevel = firstLevel;
intelObj->lastLevel = lastLevel;
}
/**
* Copies the image's contents at its level into the object's miptree,
* and updates the image to point at the object's miptree.
*/
static void
copy_image_data_to_tree(struct intel_context *intel,
struct intel_texture_object *intelObj,
struct intel_texture_image *intelImage)
{
if (intelImage->mt) {
/* Copy potentially with the blitter:
*/
intel_miptree_image_copy(intel,
intelObj->mt,
intelImage->face,
intelImage->level, intelImage->mt);
intel_miptree_release(intel, &intelImage->mt);
}
else {
assert(intelImage->base.Data != NULL);
/* More straightforward upload.
*/
intel_miptree_image_data(intel,
intelObj->mt,
intelImage->face,
intelImage->level,
intelImage->base.Data,
intelImage->base.RowStride,
intelImage->base.RowStride *
intelImage->base.Height);
_mesa_align_free(intelImage->base.Data);
intelImage->base.Data = NULL;
}
intel_miptree_reference(&intelImage->mt, intelObj->mt);
}
/*
*/
GLuint
intel_finalize_mipmap_tree(struct intel_context *intel, GLuint unit)
{
struct gl_texture_object *tObj = intel->ctx.Texture.Unit[unit]._Current;
struct intel_texture_object *intelObj = intel_texture_object(tObj);
int comp_byte = 0;
int cpp;
GLuint face, i;
GLuint nr_faces = 0;
struct intel_texture_image *firstImage;
GLboolean need_flush = GL_FALSE;
/* We know/require this is true by now:
*/
assert(intelObj->base._Complete);
/* What levels must the tree include at a minimum?
*/
intel_calculate_first_last_level(intelObj);
firstImage =
intel_texture_image(intelObj->base.Image[0][intelObj->firstLevel]);
/* Fallback case:
*/
if (firstImage->base.Border ||
((firstImage->base._BaseFormat == GL_DEPTH_COMPONENT) &&
((tObj->WrapS == GL_CLAMP_TO_BORDER) ||
(tObj->WrapT == GL_CLAMP_TO_BORDER)))) {
if (intelObj->mt) {
intel_miptree_release(intel, &intelObj->mt);
}
return GL_FALSE;
}
/* If both firstImage and intelObj have a tree which can contain
* all active images, favour firstImage. Note that because of the
* completeness requirement, we know that the image dimensions
* will match.
*/
if (firstImage->mt &&
firstImage->mt != intelObj->mt &&
firstImage->mt->first_level <= intelObj->firstLevel &&
firstImage->mt->last_level >= intelObj->lastLevel) {
if (intelObj->mt)
intel_miptree_release(intel, &intelObj->mt);
intel_miptree_reference(&intelObj->mt, firstImage->mt);
}
if (firstImage->base.IsCompressed) {
comp_byte = intel_compressed_num_bytes(firstImage->base.TexFormat->MesaFormat);
cpp = comp_byte;
}
else cpp = firstImage->base.TexFormat->TexelBytes;
/* Check tree can hold all active levels. Check tree matches
* target, imageFormat, etc.
*
* XXX: For some layouts (eg i945?), the test might have to be
* first_level == firstLevel, as the tree isn't valid except at the
* original start level. Hope to get around this by
* programming minLod, maxLod, baseLevel into the hardware and
* leaving the tree alone.
*/
if (intelObj->mt &&
(intelObj->mt->target != intelObj->base.Target ||
intelObj->mt->internal_format != firstImage->base.InternalFormat ||
intelObj->mt->first_level != intelObj->firstLevel ||
intelObj->mt->last_level != intelObj->lastLevel ||
intelObj->mt->width0 != firstImage->base.Width ||
intelObj->mt->height0 != firstImage->base.Height ||
intelObj->mt->depth0 != firstImage->base.Depth ||
intelObj->mt->cpp != cpp ||
intelObj->mt->compressed != firstImage->base.IsCompressed)) {
intel_miptree_release(intel, &intelObj->mt);
}
/* May need to create a new tree:
*/
if (!intelObj->mt) {
intelObj->mt = intel_miptree_create(intel,
intelObj->base.Target,
firstImage->base.InternalFormat,
intelObj->firstLevel,
intelObj->lastLevel,
firstImage->base.Width,
firstImage->base.Height,
firstImage->base.Depth,
cpp,
comp_byte);
}
/* Pull in any images not in the object's tree:
*/
nr_faces = (intelObj->base.Target == GL_TEXTURE_CUBE_MAP) ? 6 : 1;
for (face = 0; face < nr_faces; face++) {
for (i = intelObj->firstLevel; i <= intelObj->lastLevel; i++) {
struct intel_texture_image *intelImage =
intel_texture_image(intelObj->base.Image[face][i]);
/* Need to import images in main memory or held in other trees.
*/
if (intelObj->mt != intelImage->mt) {
copy_image_data_to_tree(intel, intelObj, intelImage);
need_flush = GL_TRUE;
}
}
}
#ifdef I915
/* XXX: what is this flush about?
* On 965, it causes a batch flush in the middle of the state relocation
* emits, which means that the eventual rendering doesn't have all of the
* required relocations in place.
*/
if (need_flush)
intel_batchbuffer_flush(intel->batch);
#endif
return GL_TRUE;
}
void
intel_tex_map_level_images(struct intel_context *intel,
struct intel_texture_object *intelObj,
int level)
{
GLuint nr_faces = (intelObj->base.Target == GL_TEXTURE_CUBE_MAP) ? 6 : 1;
GLuint face;
for (face = 0; face < nr_faces; face++) {
struct intel_texture_image *intelImage =
intel_texture_image(intelObj->base.Image[face][level]);
if (intelImage->mt) {
intelImage->base.Data =
intel_miptree_image_map(intel,
intelImage->mt,
intelImage->face,
intelImage->level,
&intelImage->base.RowStride,
intelImage->base.ImageOffsets);
/* convert stride to texels, not bytes */
intelImage->base.RowStride /= intelImage->mt->cpp;
/* intelImage->base.ImageStride /= intelImage->mt->cpp; */
}
}
}
void
intel_tex_unmap_level_images(struct intel_context *intel,
struct intel_texture_object *intelObj,
int level)
{
GLuint nr_faces = (intelObj->base.Target == GL_TEXTURE_CUBE_MAP) ? 6 : 1;
GLuint face;
for (face = 0; face < nr_faces; face++) {
struct intel_texture_image *intelImage =
intel_texture_image(intelObj->base.Image[face][level]);
if (intelImage->mt) {
intel_miptree_image_unmap(intel, intelImage->mt);
intelImage->base.Data = NULL;
}
}
}
void
intel_tex_map_images(struct intel_context *intel,
struct intel_texture_object *intelObj)
{
int i;
DBG("%s\n", __FUNCTION__);
for (i = intelObj->firstLevel; i <= intelObj->lastLevel; i++)
intel_tex_map_level_images(intel, intelObj, i);
}
void
intel_tex_unmap_images(struct intel_context *intel,
struct intel_texture_object *intelObj)
{
int i;
for (i = intelObj->firstLevel; i <= intelObj->lastLevel; i++)
intel_tex_unmap_level_images(intel, intelObj, i);
}