Esempio n. 1
0
void r300SetTexOffset(__DRIcontext * pDRICtx, GLint texname,
		      unsigned long long offset, GLint depth, GLuint pitch)
{
	r300ContextPtr rmesa = pDRICtx->driverPrivate;
	struct gl_texture_object *tObj =
	    _mesa_lookup_texture(rmesa->radeon.glCtx, texname);
	radeonTexObjPtr t = radeon_tex_obj(tObj);
	uint32_t pitch_val;

	if (!tObj)
		return;

	t->image_override = GL_TRUE;

	if (!offset)
		return;

	t->bo = NULL;
	t->override_offset = offset;
	t->pp_txpitch &= (1 << 13) -1;
	pitch_val = pitch;

	switch (depth) {
	case 32:
		t->pp_txformat = R300_EASY_TX_FORMAT(X, Y, Z, W, W8Z8Y8X8);
		t->pp_txfilter |= tx_table[2].filter;
		pitch_val /= 4;
		break;
	case 24:
	default:
		t->pp_txformat = R300_EASY_TX_FORMAT(X, Y, Z, ONE, W8Z8Y8X8);
		t->pp_txfilter |= tx_table[4].filter;
		pitch_val /= 4;
		break;
	case 16:
		t->pp_txformat = R300_EASY_TX_FORMAT(X, Y, Z, ONE, Z5Y6X5);
		t->pp_txfilter |= tx_table[5].filter;
		pitch_val /= 2;
		break;
	}
	pitch_val--;

	t->pp_txpitch |= pitch_val;
}
Esempio n. 2
0
/* Translate a pipe_format into a useful texture format for sampling.
 *
 * Some special formats are translated directly using R300_EASY_TX_FORMAT,
 * but the majority of them is translated in a generic way, automatically
 * supporting all the formats hw can support.
 *
 * R300_EASY_TX_FORMAT swizzles the texture.
 * Note the signature of R300_EASY_TX_FORMAT:
 *   R300_EASY_TX_FORMAT(B, G, R, A, FORMAT);
 *
 * The FORMAT specifies how the texture sampler will treat the texture, and
 * makes available X, Y, Z, W, ZERO, and ONE for swizzling. */
uint32_t r300_translate_texformat(enum pipe_format format,
                                  const unsigned char *swizzle_view,
                                  boolean is_r500,
                                  boolean dxtc_swizzle)
{
    uint32_t result = 0;
    const struct util_format_description *desc;
    unsigned i;
    boolean uniform = TRUE;
    const uint32_t sign_bit[4] = {
        R300_TX_FORMAT_SIGNED_X,
        R300_TX_FORMAT_SIGNED_Y,
        R300_TX_FORMAT_SIGNED_Z,
        R300_TX_FORMAT_SIGNED_W,
    };

    desc = util_format_description(format);

    /* Colorspace (return non-RGB formats directly). */
    switch (desc->colorspace) {
        /* Depth stencil formats.
         * Swizzles are added in r300_merge_textures_and_samplers. */
        case UTIL_FORMAT_COLORSPACE_ZS:
            switch (format) {
                case PIPE_FORMAT_Z16_UNORM:
                    return R300_TX_FORMAT_X16;
                case PIPE_FORMAT_X8Z24_UNORM:
                case PIPE_FORMAT_S8_USCALED_Z24_UNORM:
                    if (is_r500)
                        return R500_TX_FORMAT_Y8X24;
                    else
                        return R300_TX_FORMAT_Y16X16;
                default:
                    return ~0; /* Unsupported. */
            }

        /* YUV formats. */
        case UTIL_FORMAT_COLORSPACE_YUV:
            result |= R300_TX_FORMAT_YUV_TO_RGB;

            switch (format) {
                case PIPE_FORMAT_UYVY:
                    return R300_EASY_TX_FORMAT(X, Y, Z, ONE, YVYU422) | result;
                case PIPE_FORMAT_YUYV:
                    return R300_EASY_TX_FORMAT(X, Y, Z, ONE, VYUY422) | result;
                default:
                    return ~0; /* Unsupported/unknown. */
            }

        /* Add gamma correction. */
        case UTIL_FORMAT_COLORSPACE_SRGB:
            result |= R300_TX_FORMAT_GAMMA;
            break;

        default:
            switch (format) {
                /* Same as YUV but without the YUR->RGB conversion. */
                case PIPE_FORMAT_R8G8_B8G8_UNORM:
                    return R300_EASY_TX_FORMAT(X, Y, Z, ONE, YVYU422) | result;
                case PIPE_FORMAT_G8R8_G8B8_UNORM:
                    return R300_EASY_TX_FORMAT(X, Y, Z, ONE, VYUY422) | result;
                default:;
            }
    }

    result |= r300_get_swizzle_combined(desc->swizzle, swizzle_view,
                    util_format_is_compressed(format) && dxtc_swizzle);

    /* S3TC formats. */
    if (desc->layout == UTIL_FORMAT_LAYOUT_S3TC) {
        if (!util_format_s3tc_enabled) {
            return ~0; /* Unsupported. */
        }

        switch (format) {
            case PIPE_FORMAT_DXT1_RGB:
            case PIPE_FORMAT_DXT1_RGBA:
            case PIPE_FORMAT_DXT1_SRGB:
            case PIPE_FORMAT_DXT1_SRGBA:
                return R300_TX_FORMAT_DXT1 | result;
            case PIPE_FORMAT_DXT3_RGBA:
            case PIPE_FORMAT_DXT3_SRGBA:
                return R300_TX_FORMAT_DXT3 | result;
            case PIPE_FORMAT_DXT5_RGBA:
            case PIPE_FORMAT_DXT5_SRGBA:
                return R300_TX_FORMAT_DXT5 | result;
            default:
                return ~0; /* Unsupported/unknown. */
        }
    }

    /* Add sign. */
    for (i = 0; i < desc->nr_channels; i++) {
        if (desc->channel[i].type == UTIL_FORMAT_TYPE_SIGNED) {
            result |= sign_bit[i];
        }
    }

    /* This is truly a special format.
     * It stores R8G8 and B is computed using sqrt(1 - R^2 - G^2)
     * in the sampler unit. Also known as D3DFMT_CxV8U8. */
    if (format == PIPE_FORMAT_R8G8Bx_SNORM) {
        return R300_TX_FORMAT_CxV8U8 | result;
    }

    /* RGTC formats. */
    if (desc->layout == UTIL_FORMAT_LAYOUT_RGTC) {
        switch (format) {
            case PIPE_FORMAT_RGTC1_UNORM:
            case PIPE_FORMAT_RGTC1_SNORM:
                return R500_TX_FORMAT_ATI1N | result;
            case PIPE_FORMAT_RGTC2_UNORM:
            case PIPE_FORMAT_RGTC2_SNORM:
                return R400_TX_FORMAT_ATI2N | result;
            default:
                return ~0; /* Unsupported/unknown. */
        }
    }

    /* See whether the components are of the same size. */
    for (i = 1; i < desc->nr_channels; i++) {
        uniform = uniform && desc->channel[0].size == desc->channel[i].size;
    }

    /* Non-uniform formats. */
    if (!uniform) {
        switch (desc->nr_channels) {
            case 3:
                if (desc->channel[0].size == 5 &&
                    desc->channel[1].size == 6 &&
                    desc->channel[2].size == 5) {
                    return R300_TX_FORMAT_Z5Y6X5 | result;
                }
                if (desc->channel[0].size == 5 &&
                    desc->channel[1].size == 5 &&
                    desc->channel[2].size == 6) {
                    return R300_TX_FORMAT_Z6Y5X5 | result;
                }
                return ~0; /* Unsupported/unknown. */

            case 4:
                if (desc->channel[0].size == 5 &&
                    desc->channel[1].size == 5 &&
                    desc->channel[2].size == 5 &&
                    desc->channel[3].size == 1) {
                    return R300_TX_FORMAT_W1Z5Y5X5 | result;
                }
                if (desc->channel[0].size == 10 &&
                    desc->channel[1].size == 10 &&
                    desc->channel[2].size == 10 &&
                    desc->channel[3].size == 2) {
                    return R300_TX_FORMAT_W2Z10Y10X10 | result;
                }
        }
        return ~0; /* Unsupported/unknown. */
    }

    /* And finally, uniform formats. */
    switch (desc->channel[0].type) {
        case UTIL_FORMAT_TYPE_UNSIGNED:
        case UTIL_FORMAT_TYPE_SIGNED:
            if (!desc->channel[0].normalized &&
                desc->colorspace != UTIL_FORMAT_COLORSPACE_SRGB) {
                return ~0;
            }

            switch (desc->channel[0].size) {
                case 4:
                    switch (desc->nr_channels) {
                        case 2:
                            return R300_TX_FORMAT_Y4X4 | result;
                        case 4:
                            return R300_TX_FORMAT_W4Z4Y4X4 | result;
                    }
                    return ~0;

                case 8:
                    switch (desc->nr_channels) {
                        case 1:
                            return R300_TX_FORMAT_X8 | result;
                        case 2:
                            return R300_TX_FORMAT_Y8X8 | result;
                        case 4:
                            return R300_TX_FORMAT_W8Z8Y8X8 | result;
                    }
                    return ~0;

                case 16:
                    switch (desc->nr_channels) {
                        case 1:
                            return R300_TX_FORMAT_X16 | result;
                        case 2:
                            return R300_TX_FORMAT_Y16X16 | result;
                        case 4:
                            return R300_TX_FORMAT_W16Z16Y16X16 | result;
                    }
            }
            return ~0;

        case UTIL_FORMAT_TYPE_FLOAT:
            switch (desc->channel[0].size) {
                case 16:
                    switch (desc->nr_channels) {
                        case 1:
                            return R300_TX_FORMAT_16F | result;
                        case 2:
                            return R300_TX_FORMAT_16F_16F | result;
                        case 4:
                            return R300_TX_FORMAT_16F_16F_16F_16F | result;
                    }
                    return ~0;

                case 32:
                    switch (desc->nr_channels) {
                        case 1:
                            return R300_TX_FORMAT_32F | result;
                        case 2:
                            return R300_TX_FORMAT_32F_32F | result;
                        case 4:
                            return R300_TX_FORMAT_32F_32F_32F_32F | result;
                    }
            }
    }

    return ~0; /* Unsupported/unknown. */
}
Esempio n. 3
0
void r300SetTexBuffer2(__DRIcontext *pDRICtx, GLint target, GLint glx_texture_format, __DRIdrawable *dPriv)
{
	struct gl_texture_unit *texUnit;
	struct gl_texture_object *texObj;
	struct gl_texture_image *texImage;
	struct radeon_renderbuffer *rb;
	radeon_texture_image *rImage;
	radeonContextPtr radeon;
	r300ContextPtr rmesa;
	struct radeon_framebuffer *rfb;
	radeonTexObjPtr t;
	uint32_t pitch_val;
	uint32_t internalFormat, type, format;

	type = GL_BGRA;
	format = GL_UNSIGNED_BYTE;
	internalFormat = (glx_texture_format == GLX_TEXTURE_FORMAT_RGB_EXT ? 3 : 4);

	radeon = pDRICtx->driverPrivate;
	rmesa = pDRICtx->driverPrivate;

	rfb = dPriv->driverPrivate;
        texUnit = &radeon->glCtx->Texture.Unit[radeon->glCtx->Texture.CurrentUnit];
	texObj = _mesa_select_tex_object(radeon->glCtx, texUnit, target);
        texImage = _mesa_get_tex_image(radeon->glCtx, texObj, target, 0);

	rImage = get_radeon_texture_image(texImage);
	t = radeon_tex_obj(texObj);
        if (t == NULL) {
    	    return;
    	}

	radeon_update_renderbuffers(pDRICtx, dPriv);
	/* back & depth buffer are useless free them right away */
	rb = (void*)rfb->base.Attachment[BUFFER_DEPTH].Renderbuffer;
	if (rb && rb->bo) {
		radeon_bo_unref(rb->bo);
        rb->bo = NULL;
	}
	rb = (void*)rfb->base.Attachment[BUFFER_BACK_LEFT].Renderbuffer;
	if (rb && rb->bo) {
		radeon_bo_unref(rb->bo);
		rb->bo = NULL;
	}
	rb = rfb->color_rb[0];
	if (rb->bo == NULL) {
		/* Failed to BO for the buffer */
		return;
	}
	
	_mesa_lock_texture(radeon->glCtx, texObj);
	if (t->bo) {
		radeon_bo_unref(t->bo);
		t->bo = NULL;
	}
	if (rImage->bo) {
		radeon_bo_unref(rImage->bo);
		rImage->bo = NULL;
	}

	radeon_miptree_unreference(&t->mt);
	radeon_miptree_unreference(&rImage->mt);

	_mesa_init_teximage_fields(radeon->glCtx, target, texImage,
				   rb->base.Width, rb->base.Height, 1, 0, rb->cpp);
	texImage->RowStride = rb->pitch / rb->cpp;
	rImage->bo = rb->bo;
	radeon_bo_ref(rImage->bo);
	t->bo = rb->bo;
	radeon_bo_ref(t->bo);
	t->tile_bits = 0;
	t->image_override = GL_TRUE;
	t->override_offset = 0;
	t->pp_txpitch &= (1 << 13) -1;
	pitch_val = rb->pitch;
	switch (rb->cpp) {
	case 4:
		if (glx_texture_format == GLX_TEXTURE_FORMAT_RGB_EXT)
			t->pp_txformat = R300_EASY_TX_FORMAT(X, Y, Z, ONE, W8Z8Y8X8);
		else
			t->pp_txformat = R300_EASY_TX_FORMAT(X, Y, Z, W, W8Z8Y8X8);
		t->pp_txfilter |= tx_table[2].filter;
		pitch_val /= 4;
		break;
	case 3:
	default:
		t->pp_txformat = R300_EASY_TX_FORMAT(X, Y, Z, ONE, W8Z8Y8X8);
		t->pp_txfilter |= tx_table[4].filter;
		pitch_val /= 4;
		break;
	case 2:
		t->pp_txformat = R300_EASY_TX_FORMAT(X, Y, Z, ONE, Z5Y6X5);
		t->pp_txfilter |= tx_table[5].filter;
		pitch_val /= 2;
		break;
	}
	pitch_val--;
	t->pp_txsize = (((R300_TX_WIDTHMASK_MASK & ((rb->base.Width - 1) << R300_TX_WIDTHMASK_SHIFT)))
			| ((R300_TX_HEIGHTMASK_MASK & ((rb->base.Height - 1) << R300_TX_HEIGHTMASK_SHIFT))));
	t->pp_txsize |= R300_TX_SIZE_TXPITCH_EN;
	t->pp_txpitch |= pitch_val;

	if (rmesa->radeon.radeonScreen->chip_family >= CHIP_FAMILY_RV515) {
	    if (rb->base.Width > 2048)
		t->pp_txpitch |= R500_TXWIDTH_BIT11;
            else
		t->pp_txpitch &= ~R500_TXWIDTH_BIT11;
	    if (rb->base.Height > 2048)
		t->pp_txpitch |= R500_TXHEIGHT_BIT11;
            else
		t->pp_txpitch &= ~R500_TXHEIGHT_BIT11;
	}
	t->validated = GL_TRUE;
	_mesa_unlock_texture(radeon->glCtx, texObj);
	return;
}
Esempio n. 4
0
void r300SetDepthTexMode(struct gl_texture_object *tObj)
{
	static const GLuint formats[3][3] = {
		{
			R300_EASY_TX_FORMAT(X, X, X, ONE, X16),
			R300_EASY_TX_FORMAT(X, X, X, X, X16),
			R300_EASY_TX_FORMAT(ZERO, ZERO, ZERO, X, X16),
		},
		{
			R300_EASY_TX_FORMAT(Y, Y, Y, ONE, X24_Y8),
			R300_EASY_TX_FORMAT(Y, Y, Y, Y, X24_Y8),
			R300_EASY_TX_FORMAT(ZERO, ZERO, ZERO, Y, X24_Y8),
		},
		{
			R300_EASY_TX_FORMAT(X, X, X, ONE, X32),
			R300_EASY_TX_FORMAT(X, X, X, X, X32),
			R300_EASY_TX_FORMAT(ZERO, ZERO, ZERO, X, X32),
		},
	};
	const GLuint *format;
	radeonTexObjPtr t;

	if (!tObj)
		return;

	t = radeon_tex_obj(tObj);

	switch (tObj->Image[0][tObj->BaseLevel]->TexFormat) {
	case MESA_FORMAT_Z16:
		format = formats[0];
		break;
	case MESA_FORMAT_S8_Z24:
		format = formats[1];
		break;
	case MESA_FORMAT_Z32:
		format = formats[2];
		break;
	default:
		/* Error...which should have already been caught by higher
		 * levels of Mesa.
		 */
		ASSERT(0);
		return;
	}

	switch (tObj->DepthMode) {
	case GL_LUMINANCE:
		t->pp_txformat = format[0];
		break;
	case GL_INTENSITY:
		t->pp_txformat = format[1];
		break;
	case GL_ALPHA:
		t->pp_txformat = format[2];
		break;
	default:
		/* Error...which should have already been caught by higher
		 * levels of Mesa.
		 */
		ASSERT(0);
		return;
	}
}
Esempio n. 5
0
/*
 * Note that the _REV formats are the same as the non-REV formats.  This is
 * because the REV and non-REV formats are identical as a byte string, but
 * differ when accessed as 16-bit or 32-bit words depending on the endianness of
 * the host.  Since the textures are transferred to the R300 as a byte string
 * (i.e. without any byte-swapping), the R300 sees the REV and non-REV formats
 * identically.  -- paulus
 */

static const struct tx_table {
	GLuint format, filter, flag;
} tx_table[] = {
	/* *INDENT-OFF* */
#ifdef MESA_LITTLE_ENDIAN
	_ASSIGN(RGBA8888, R300_EASY_TX_FORMAT(Y, Z, W, X, W8Z8Y8X8)),
	_ASSIGN(RGBA8888_REV, R300_EASY_TX_FORMAT(Z, Y, X, W, W8Z8Y8X8)),
	_ASSIGN(ARGB8888, R300_EASY_TX_FORMAT(X, Y, Z, W, W8Z8Y8X8)),
	_ASSIGN(ARGB8888_REV, R300_EASY_TX_FORMAT(W, Z, Y, X, W8Z8Y8X8)),
#else
	_ASSIGN(RGBA8888, R300_EASY_TX_FORMAT(Z, Y, X, W, W8Z8Y8X8)),
	_ASSIGN(RGBA8888_REV, R300_EASY_TX_FORMAT(Y, Z, W, X, W8Z8Y8X8)),
	_ASSIGN(ARGB8888, R300_EASY_TX_FORMAT(W, Z, Y, X, W8Z8Y8X8)),
	_ASSIGN(ARGB8888_REV, R300_EASY_TX_FORMAT(X, Y, Z, W, W8Z8Y8X8)),
#endif
	_ASSIGN(XRGB8888, R300_EASY_TX_FORMAT(X, Y, Z, ONE, W8Z8Y8X8)),
	_ASSIGN(RGB888, R300_EASY_TX_FORMAT(X, Y, Z, ONE, W8Z8Y8X8)),
	_ASSIGN(RGB565, R300_EASY_TX_FORMAT(X, Y, Z, ONE, Z5Y6X5)),
	_ASSIGN(RGB565_REV, R300_EASY_TX_FORMAT(X, Y, Z, ONE, Z5Y6X5)),
	_ASSIGN(ARGB4444, R300_EASY_TX_FORMAT(X, Y, Z, W, W4Z4Y4X4)),
	_ASSIGN(ARGB4444_REV, R300_EASY_TX_FORMAT(X, Y, Z, W, W4Z4Y4X4)),
Esempio n. 6
0
/* Translate a pipe_format into a useful texture format for sampling.
 *
 * Some special formats are translated directly using R300_EASY_TX_FORMAT,
 * but the majority of them is translated in a generic way, automatically
 * supporting all the formats hw can support.
 *
 * R300_EASY_TX_FORMAT swizzles the texture.
 * Note the signature of R300_EASY_TX_FORMAT:
 *   R300_EASY_TX_FORMAT(B, G, R, A, FORMAT);
 *
 * The FORMAT specifies how the texture sampler will treat the texture, and
 * makes available X, Y, Z, W, ZERO, and ONE for swizzling. */
static uint32_t r300_translate_texformat(enum pipe_format format)
{
    uint32_t result = 0;
    const struct util_format_description *desc;
    unsigned components = 0, i;
    boolean uniform = TRUE;
    const uint32_t swizzle_shift[4] = {
        R300_TX_FORMAT_R_SHIFT,
        R300_TX_FORMAT_G_SHIFT,
        R300_TX_FORMAT_B_SHIFT,
        R300_TX_FORMAT_A_SHIFT
    };
    const uint32_t swizzle[4] = {
        R300_TX_FORMAT_X,
        R300_TX_FORMAT_Y,
        R300_TX_FORMAT_Z,
        R300_TX_FORMAT_W
    };
    const uint32_t sign_bit[4] = {
        R300_TX_FORMAT_SIGNED_X,
        R300_TX_FORMAT_SIGNED_Y,
        R300_TX_FORMAT_SIGNED_Z,
        R300_TX_FORMAT_SIGNED_W,
    };

    desc = util_format_description(format);

    /* Colorspace (return non-RGB formats directly). */
    switch (desc->colorspace) {
    /* Depth stencil formats. */
    case UTIL_FORMAT_COLORSPACE_ZS:
        switch (format) {
        case PIPE_FORMAT_Z16_UNORM:
            return R300_EASY_TX_FORMAT(X, X, X, X, X16);
        case PIPE_FORMAT_X8Z24_UNORM:
        case PIPE_FORMAT_S8Z24_UNORM:
            return R300_EASY_TX_FORMAT(X, X, X, X, W24_FP);
        default:
            return ~0; /* Unsupported. */
        }

    /* YUV formats. */
    case UTIL_FORMAT_COLORSPACE_YUV:
        result |= R300_TX_FORMAT_YUV_TO_RGB;

        switch (format) {
        case PIPE_FORMAT_UYVY:
            return R300_EASY_TX_FORMAT(X, Y, Z, ONE, YVYU422) | result;
        case PIPE_FORMAT_YUYV:
            return R300_EASY_TX_FORMAT(X, Y, Z, ONE, VYUY422) | result;
        default:
            return ~0; /* Unsupported/unknown. */
        }

    /* Add gamma correction. */
    case UTIL_FORMAT_COLORSPACE_SRGB:
        result |= R300_TX_FORMAT_GAMMA;
        break;

    default:
        ;
    }

    /* Add swizzle. */
    for (i = 0; i < 4; i++) {
        switch (desc->swizzle[i]) {
        case UTIL_FORMAT_SWIZZLE_X:
        case UTIL_FORMAT_SWIZZLE_NONE:
            result |= swizzle[0] << swizzle_shift[i];
            break;
        case UTIL_FORMAT_SWIZZLE_Y:
            result |= swizzle[1] << swizzle_shift[i];
            break;
        case UTIL_FORMAT_SWIZZLE_Z:
            result |= swizzle[2] << swizzle_shift[i];
            break;
        case UTIL_FORMAT_SWIZZLE_W:
            result |= swizzle[3] << swizzle_shift[i];
            break;
        case UTIL_FORMAT_SWIZZLE_0:
            result |= R300_TX_FORMAT_ZERO << swizzle_shift[i];
            break;
        case UTIL_FORMAT_SWIZZLE_1:
            result |= R300_TX_FORMAT_ONE << swizzle_shift[i];
            break;
        default:
            return ~0; /* Unsupported. */
        }
    }

    /* Compressed formats. */
    if (desc->layout == UTIL_FORMAT_LAYOUT_COMPRESSED) {
        switch (format) {
        case PIPE_FORMAT_DXT1_RGB:
        case PIPE_FORMAT_DXT1_RGBA:
        case PIPE_FORMAT_DXT1_SRGB:
        case PIPE_FORMAT_DXT1_SRGBA:
            return R300_TX_FORMAT_DXT1 | result;
        case PIPE_FORMAT_DXT3_RGBA:
        case PIPE_FORMAT_DXT3_SRGBA:
            return R300_TX_FORMAT_DXT3 | result;
        case PIPE_FORMAT_DXT5_RGBA:
        case PIPE_FORMAT_DXT5_SRGBA:
            return R300_TX_FORMAT_DXT5 | result;
        default:
            return ~0; /* Unsupported/unknown. */
        }
    }

    /* Get the number of components. */
    for (i = 0; i < 4; i++) {
        if (desc->channel[i].type != UTIL_FORMAT_TYPE_VOID) {
            ++components;
        }
    }

    /* Add sign. */
    for (i = 0; i < components; i++) {
        if (desc->channel[i].type == UTIL_FORMAT_TYPE_SIGNED) {
            result |= sign_bit[i];
        }
    }

    /* See whether the components are of the same size. */
    for (i = 1; i < components; i++) {
        uniform = uniform && desc->channel[0].size == desc->channel[i].size;
    }

    /* Non-uniform formats. */
    if (!uniform) {
        switch (components) {
        case 3:
            if (desc->channel[0].size == 5 &&
                    desc->channel[1].size == 6 &&
                    desc->channel[2].size == 5) {
                return R300_TX_FORMAT_Z5Y6X5 | result;
            }
            if (desc->channel[0].size == 5 &&
                    desc->channel[1].size == 5 &&
                    desc->channel[2].size == 6) {
                return R300_TX_FORMAT_Z6Y5X5 | result;
            }
            return ~0; /* Unsupported/unknown. */

        case 4:
            if (desc->channel[0].size == 5 &&
                    desc->channel[1].size == 5 &&
                    desc->channel[2].size == 5 &&
                    desc->channel[3].size == 1) {
                return R300_TX_FORMAT_W1Z5Y5X5 | result;
            }
            if (desc->channel[0].size == 10 &&
                    desc->channel[1].size == 10 &&
                    desc->channel[2].size == 10 &&
                    desc->channel[3].size == 2) {
                return R300_TX_FORMAT_W2Z10Y10X10 | result;
            }
        }
        return ~0; /* Unsupported/unknown. */
    }

    /* And finally, uniform formats. */
    switch (desc->channel[0].type) {
    case UTIL_FORMAT_TYPE_UNSIGNED:
    case UTIL_FORMAT_TYPE_SIGNED:
        if (!desc->channel[0].normalized &&
                desc->colorspace != UTIL_FORMAT_COLORSPACE_SRGB) {
            return ~0;
        }

        switch (desc->channel[0].size) {
        case 4:
            switch (components) {
            case 2:
                return R300_TX_FORMAT_Y4X4 | result;
            case 4:
                return R300_TX_FORMAT_W4Z4Y4X4 | result;
            }
            return ~0;

        case 8:
            switch (components) {
            case 1:
                return R300_TX_FORMAT_X8 | result;
            case 2:
                return R300_TX_FORMAT_Y8X8 | result;
            case 4:
                return R300_TX_FORMAT_W8Z8Y8X8 | result;
            }
            return ~0;

        case 16:
            switch (components) {
            case 1:
                return R300_TX_FORMAT_X16 | result;
            case 2:
                return R300_TX_FORMAT_Y16X16 | result;
            case 4:
                return R300_TX_FORMAT_W16Z16Y16X16 | result;
            }
        }
        return ~0;

        /* XXX Enable float textures here. */
#if 0
    case UTIL_FORMAT_TYPE_FLOAT:
        switch (desc->channel[0].size) {
        case 16:
            switch (components) {
            case 1:
                return R300_TX_FORMAT_16F | result;
            case 2:
                return R300_TX_FORMAT_16F_16F | result;
            case 4:
                return R300_TX_FORMAT_16F_16F_16F_16F | result;
            }
            return ~0;

        case 32:
            switch (components) {
            case 1:
                return R300_TX_FORMAT_32F | result;
            case 2:
                return R300_TX_FORMAT_32F_32F | result;
            case 4:
                return R300_TX_FORMAT_32F_32F_32F_32F | result;
            }
        }
#endif
    }

    return ~0; /* Unsupported/unknown. */
}