[Nouveau] [WIP PATCH] dri/nouveau: Add S3TC support for nv20.
Ben Skeggs
skeggsb at gmail.com
Tue Apr 24 05:35:21 PDT 2012
On Fri, 2012-04-06 at 17:40 +0200, Viktor Novotný wrote:
> ---
> Hi,
Hey Viktor!
Thanks for the patch!
>
> this is still WIP, but already passes piglit's s3tc-teximage, s3tc-texsubimage and fbo-generatemipmap-formats(s3tc tests)
> and even Wolfenstein:Enemy-Territory works on my nv25. It's based on Ben's newlib branch. I have few issues though:
> 1) So far it needs libtxc_dxtn, but I might expose the s3tc extensions even without encoder using driconf option -
> Is that desirable?
> 2) Looking at blob's dedma'd valgrind-mmt dumps it seems blob uses pitch no smaller than 64 in miptree,
> but for me everything works as it is. Does it make any difference?
> 2) I am not sure about computing the offsets in teximage_map - it works like this, but can somebody confirm it's ok?
> 3) If somebody can give me some feedback on the style etc., please do.
> 4) S3TC texture seem to be supported also on nv10, I have nv11 somewhere so I might be able to add support to it too,
Curro, are you able to take a look over this and give Viktor some
feedback? You're probably best acquainted with the vieux code :)
Ben.
> but I don't have nv04, then again, I think it might not support S3TC?
>
> If I you think the patch is mostly OK, I will process your feedback, split generic and nv20 specific part and resend it.
>
> Regards
> Viktor
>
> src/mesa/drivers/dri/nouveau/nouveau_surface.c | 14 ++-
> src/mesa/drivers/dri/nouveau/nouveau_texture.c | 143 ++++++++++++++++++-----
> src/mesa/drivers/dri/nouveau/nouveau_util.h | 19 +++
> src/mesa/drivers/dri/nouveau/nv04_surface.c | 17 +++-
> src/mesa/drivers/dri/nouveau/nv20_context.c | 4 +
> src/mesa/drivers/dri/nouveau/nv20_state_tex.c | 10 ++
> 6 files changed, 172 insertions(+), 35 deletions(-)
>
> diff --git a/src/mesa/drivers/dri/nouveau/nouveau_surface.c b/src/mesa/drivers/dri/nouveau/nouveau_surface.c
> index f252114..349000a 100644
> --- a/src/mesa/drivers/dri/nouveau/nouveau_surface.c
> +++ b/src/mesa/drivers/dri/nouveau/nouveau_surface.c
> @@ -28,6 +28,8 @@
> #include "nouveau_context.h"
> #include "nouveau_util.h"
>
> +#include "main/formats.h"
> +
> void
> nouveau_surface_alloc(struct gl_context *ctx, struct nouveau_surface *s,
> enum nouveau_surface_layout layout,
> @@ -36,6 +38,8 @@ nouveau_surface_alloc(struct gl_context *ctx, struct nouveau_surface *s,
> {
> union nouveau_bo_config config = {};
> int ret, cpp = _mesa_get_format_bytes(format);
> + int pitch = _mesa_format_row_stride(format, width);
> + unsigned size;
>
> nouveau_bo_ref(NULL, &s->bo);
>
> @@ -45,7 +49,7 @@ nouveau_surface_alloc(struct gl_context *ctx, struct nouveau_surface *s,
> .width = width,
> .height = height,
> .cpp = cpp,
> - .pitch = width * cpp,
> + .pitch = pitch,
> };
>
> if (layout == TILED) {
> @@ -64,8 +68,12 @@ nouveau_surface_alloc(struct gl_context *ctx, struct nouveau_surface *s,
> s->pitch = align(s->pitch, 64);
> }
>
> - ret = nouveau_bo_new(context_dev(ctx), flags, 0, s->pitch * height,
> - &config, &s->bo);
> + if (_mesa_is_format_compressed(format))
> + size = s->pitch * nouveau_format_get_nblocksy(format, height);
> + else
> + size = s->pitch * height;
> +
> + ret = nouveau_bo_new(context_dev(ctx), flags, 0, size, &config, &s->bo);
> assert(!ret);
> }
>
> diff --git a/src/mesa/drivers/dri/nouveau/nouveau_texture.c b/src/mesa/drivers/dri/nouveau/nouveau_texture.c
> index 643b890..52f0259 100644
> --- a/src/mesa/drivers/dri/nouveau/nouveau_texture.c
> +++ b/src/mesa/drivers/dri/nouveau/nouveau_texture.c
> @@ -91,6 +91,7 @@ nouveau_teximage_map(struct gl_context *ctx, struct gl_texture_image *ti,
> if (s->bo) {
> if (!(access & GL_MAP_READ_BIT) &&
> nouveau_pushbuf_refd(context_push(ctx), s->bo)) {
> + unsigned size;
> /*
> * Heuristic: use a bounce buffer to pipeline
> * teximage transfers.
> @@ -104,7 +105,8 @@ nouveau_teximage_map(struct gl_context *ctx, struct gl_texture_image *ti,
> nti->transfer.x = x;
> nti->transfer.y = y;
>
> - nti->base.Map = nouveau_get_scratch(ctx, st->pitch * h,
> + size = nouveau_format_get_nblocksx(st->format, h) * st->pitch;
> + nti->base.Map = nouveau_get_scratch(ctx, size,
> &st->bo, &st->offset);
>
> } else {
> @@ -120,7 +122,10 @@ nouveau_teximage_map(struct gl_context *ctx, struct gl_texture_image *ti,
> assert(!ret);
> }
>
> - nti->base.Map = s->bo->map + y * s->pitch + x * s->cpp;
> + nti->base.Map = s->bo->map +
> + nouveau_format_get_nblocksy(s->format, y) * s->pitch +
> + nouveau_format_get_nblocksx(s->format, x) * s->cpp;
> +
> }
> }
> }
> @@ -166,6 +171,7 @@ nouveau_map_texture_image(struct gl_context *ctx,
> if (s->bo) {
> if (!(mode & GL_MAP_READ_BIT) &&
> nouveau_pushbuf_refd(context_push(ctx), s->bo)) {
> + unsigned size;
> /*
> * Heuristic: use a bounce buffer to pipeline
> * teximage transfers.
> @@ -179,8 +185,8 @@ nouveau_map_texture_image(struct gl_context *ctx,
> nti->transfer.x = x;
> nti->transfer.y = y;
>
> - *map = nouveau_get_scratch(ctx, st->pitch * h,
> - &st->bo, &st->offset);
> + size = nouveau_format_get_nblocksy(st->format, h) * st->pitch;
> + *map = nouveau_get_scratch(ctx, size, &st->bo, &st->offset);
> *stride = st->pitch;
> } else {
> int ret, flags = 0;
> @@ -195,11 +201,15 @@ nouveau_map_texture_image(struct gl_context *ctx,
> assert(!ret);
> }
>
> - *map = s->bo->map + y * s->pitch + x * s->cpp;
> + *map = s->bo->map +
> + nouveau_format_get_nblocksy(s->format, y) * s->pitch +
> + nouveau_format_get_nblocksx(s->format, x) * s->cpp;
> *stride = s->pitch;
> }
> } else {
> - *map = nti->base.Map + y * s->pitch + x * s->cpp;
> + *map = nti->base.Map +
> + nouveau_format_get_nblocksy(s->format, y) * s->pitch +
> + nouveau_format_get_nblocksx(s->format, x) * s->cpp;
> *stride = s->pitch;
> }
> }
> @@ -291,7 +301,24 @@ nouveau_choose_tex_format(struct gl_context *ctx, GLint internalFormat,
> case GL_INTENSITY8:
> return MESA_FORMAT_I8;
>
> + case GL_RGB_S3TC:
> + case GL_RGB4_S3TC:
> + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
> + return MESA_FORMAT_RGB_DXT1;
> +
> + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
> + return MESA_FORMAT_RGBA_DXT1;
> +
> + case GL_RGBA_S3TC:
> + case GL_RGBA4_S3TC:
> + case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
> + return MESA_FORMAT_RGBA_DXT3;
> +
> + case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
> + return MESA_FORMAT_RGBA_DXT5;
> +
> default:
> + nouveau_error("unexpected internalFormat 0x%x\n", internalFormat);
> assert(0);
> }
> }
> @@ -358,7 +385,7 @@ relayout_texture(struct gl_context *ctx, struct gl_texture_object *t)
> struct nouveau_surface *ss = to_nouveau_texture(t)->surfaces;
> struct nouveau_surface *s = &to_nouveau_teximage(base)->surface;
> int i, ret, last = get_last_level(t);
> - unsigned size, offset = 0,
> + unsigned size, pitch, layout, offset = 0,
> width = s->width,
> height = s->height;
>
> @@ -368,7 +395,16 @@ relayout_texture(struct gl_context *ctx, struct gl_texture_object *t)
>
> /* Relayout the mipmap tree. */
> for (i = t->BaseLevel; i <= last; i++) {
> - size = width * height * s->cpp;
> +
> + if (_mesa_is_format_compressed(s->format)) {
> + layout = LINEAR;
> + pitch = _mesa_format_row_stride(s->format, width);
> + size = nouveau_format_get_nblocksy(s->format, height) * pitch;
> + } else {
> + layout = SWIZZLED;
> + pitch = width * s->cpp;
> + size = height * pitch;
> + }
>
> /* Images larger than 16B have to be aligned. */
> if (size > 16)
> @@ -376,12 +412,12 @@ relayout_texture(struct gl_context *ctx, struct gl_texture_object *t)
>
> ss[i] = (struct nouveau_surface) {
> .offset = offset,
> - .layout = SWIZZLED,
> + .layout = layout,
> .format = s->format,
> .width = width,
> .height = height,
> .cpp = s->cpp,
> - .pitch = width * s->cpp,
> + .pitch = pitch,
> };
>
> offset += size;
> @@ -458,8 +494,10 @@ nouveau_teximage(struct gl_context *ctx, GLint dims,
> struct gl_texture_image *ti,
> GLint internalFormat,
> GLint width, GLint height, GLint depth, GLint border,
> + GLsizei imageSize,
> GLenum format, GLenum type, const GLvoid *pixels,
> - const struct gl_pixelstore_attrib *packing)
> + const struct gl_pixelstore_attrib *packing,
> + GLboolean compressed)
> {
> struct gl_texture_object *t = ti->TexObject;
> const GLuint level = ti->Level;
> @@ -472,9 +510,16 @@ nouveau_teximage(struct gl_context *ctx, GLint dims,
> ti->TexFormat, width, height);
> nti->base.RowStride = s->pitch / s->cpp;
>
> - pixels = _mesa_validate_pbo_teximage(ctx, dims, width, height, depth,
> - format, type, pixels, packing,
> - "glTexImage");
> + if (compressed) {
> + pixels = _mesa_validate_pbo_compressed_teximage(ctx,
> + imageSize,
> + pixels, packing, "glCompressedTexImage");
> + } else {
> + pixels = _mesa_validate_pbo_teximage(ctx,
> + dims, width, height, depth, format, type,
> + pixels, packing, "glTexImage");
> + }
> +
> if (pixels) {
> /* Store the pixel data. */
> nouveau_teximage_map(ctx, ti, GL_MAP_WRITE_BIT,
> @@ -516,8 +561,8 @@ nouveau_teximage_1d(struct gl_context *ctx,
> const struct gl_pixelstore_attrib *packing)
> {
> nouveau_teximage(ctx, 1, ti, internalFormat,
> - width, 1, 1, border, format, type, pixels,
> - packing);
> + width, 1, 1, border, 0, format, type, pixels,
> + packing, GL_FALSE);
> }
>
> static void
> @@ -529,8 +574,8 @@ nouveau_teximage_2d(struct gl_context *ctx,
> const struct gl_pixelstore_attrib *packing)
> {
> nouveau_teximage(ctx, 2, ti, internalFormat,
> - width, height, 1, border, format, type, pixels,
> - packing);
> + width, height, 1, border, 0, format, type, pixels,
> + packing, GL_FALSE);
> }
>
> static void
> @@ -542,8 +587,20 @@ nouveau_teximage_3d(struct gl_context *ctx,
> const struct gl_pixelstore_attrib *packing)
> {
> nouveau_teximage(ctx, 3, ti, internalFormat,
> - width, height, depth, border, format, type, pixels,
> - packing);
> + width, height, depth, border, 0, format, type, pixels,
> + packing, GL_FALSE);
> +}
> +
> +static void
> +nouveau_compressed_teximage_2d(struct gl_context *ctx,
> + struct gl_texture_image *ti,
> + GLint internalFormat,
> + GLint width, GLint height, GLint border,
> + GLsizei imageSize, const GLvoid *data)
> +{
> + nouveau_teximage(ctx, 2, ti, internalFormat,
> + width, height, 1, border, imageSize, 0, 0, data,
> + &ctx->Unpack, GL_TRUE);
> }
>
> static void
> @@ -551,21 +608,30 @@ nouveau_texsubimage(struct gl_context *ctx, GLint dims,
> struct gl_texture_image *ti,
> GLint xoffset, GLint yoffset, GLint zoffset,
> GLint width, GLint height, GLint depth,
> + GLsizei imageSize,
> GLenum format, GLenum type, const void *pixels,
> - const struct gl_pixelstore_attrib *packing)
> + const struct gl_pixelstore_attrib *packing,
> + GLboolean compressed)
> {
> struct nouveau_surface *s = &to_nouveau_teximage(ti)->surface;
> struct nouveau_teximage *nti = to_nouveau_teximage(ti);
> int ret;
>
> - pixels = _mesa_validate_pbo_teximage(ctx, dims, width, height, depth,
> - format, type, pixels, packing,
> - "glTexSubImage");
> + if (compressed) {
> + pixels = _mesa_validate_pbo_compressed_teximage(ctx,
> + imageSize,
> + pixels, packing, "glCompressedTexSubImage");
> + } else {
> + pixels = _mesa_validate_pbo_teximage(ctx,
> + dims, width, height, depth, format, type,
> + pixels, packing, "glTexSubImage");
> + }
> +
> if (pixels) {
> nouveau_teximage_map(ctx, ti, GL_MAP_WRITE_BIT,
> xoffset, yoffset, width, height);
>
> - ret = _mesa_texstore(ctx, 3, ti->_BaseFormat, ti->TexFormat,
> + ret = _mesa_texstore(ctx, dims, ti->_BaseFormat, ti->TexFormat,
> s->pitch,
> &nti->base.Map,
> width, height, depth,
> @@ -591,8 +657,8 @@ nouveau_texsubimage_3d(struct gl_context *ctx,
> const struct gl_pixelstore_attrib *packing)
> {
> nouveau_texsubimage(ctx, 3, ti, xoffset, yoffset, zoffset,
> - width, height, depth, format, type, pixels,
> - packing);
> + width, height, depth, 0, format, type, pixels,
> + packing, GL_FALSE);
> }
>
> static void
> @@ -604,8 +670,8 @@ nouveau_texsubimage_2d(struct gl_context *ctx,
> const struct gl_pixelstore_attrib *packing)
> {
> nouveau_texsubimage(ctx, 2, ti, xoffset, yoffset, 0,
> - width, height, 1, format, type, pixels,
> - packing);
> + width, height, 1, 0, format, type, pixels,
> + packing, GL_FALSE);
> }
>
> static void
> @@ -616,8 +682,21 @@ nouveau_texsubimage_1d(struct gl_context *ctx,
> const struct gl_pixelstore_attrib *packing)
> {
> nouveau_texsubimage(ctx, 1, ti, xoffset, 0, 0,
> - width, 1, 1, format, type, pixels,
> - packing);
> + width, 1, 1, 0, format, type, pixels,
> + packing, GL_FALSE);
> +}
> +
> +static void
> +nouveau_compressed_texsubimage_2d(struct gl_context *ctx,
> + struct gl_texture_image *ti,
> + GLint xoffset, GLint yoffset,
> + GLsizei width, GLint height,
> + GLenum format,
> + GLint imageSize, const void *data)
> +{
> + nouveau_texsubimage(ctx, 2, ti, xoffset, yoffset, 0,
> + width, height, 1, imageSize, format, 0, data,
> + &ctx->Unpack, GL_TRUE);
> }
>
> static void
> @@ -696,6 +775,8 @@ nouveau_texture_functions_init(struct dd_function_table *functions)
> functions->TexSubImage1D = nouveau_texsubimage_1d;
> functions->TexSubImage2D = nouveau_texsubimage_2d;
> functions->TexSubImage3D = nouveau_texsubimage_3d;
> + functions->CompressedTexImage2D = nouveau_compressed_teximage_2d;
> + functions->CompressedTexSubImage2D = nouveau_compressed_texsubimage_2d;
> functions->BindTexture = nouveau_bind_texture;
> functions->MapTextureImage = nouveau_map_texture_image;
> functions->UnmapTextureImage = nouveau_unmap_texture_image;
> diff --git a/src/mesa/drivers/dri/nouveau/nouveau_util.h b/src/mesa/drivers/dri/nouveau/nouveau_util.h
> index d4cc5c4..af2b175 100644
> --- a/src/mesa/drivers/dri/nouveau/nouveau_util.h
> +++ b/src/mesa/drivers/dri/nouveau/nouveau_util.h
> @@ -207,4 +207,23 @@ get_texgen_coeff(struct gl_texgen *c)
> return NULL;
> }
>
> +static inline unsigned
> +nouveau_format_get_nblocksx(gl_format format,
> + unsigned x)
> +{
> + GLuint blockwidth;
> + GLuint blockheight;
> + _mesa_get_format_block_size(format, &blockwidth, &blockheight);
> + return (x + blockwidth - 1) / blockwidth;
> +}
> +
> +static inline unsigned
> +nouveau_format_get_nblocksy(gl_format format,
> + unsigned y)
> +{
> + GLuint blockwidth;
> + GLuint blockheight;
> + _mesa_get_format_block_size(format, &blockwidth, &blockheight);
> + return (y + blockheight - 1) / blockheight;
> +}
> #endif
> diff --git a/src/mesa/drivers/dri/nouveau/nv04_surface.c b/src/mesa/drivers/dri/nouveau/nv04_surface.c
> index b2b260d..bc3cace 100644
> --- a/src/mesa/drivers/dri/nouveau/nv04_surface.c
> +++ b/src/mesa/drivers/dri/nouveau/nv04_surface.c
> @@ -291,7 +291,7 @@ nv04_surface_copy_m2mf(struct gl_context *ctx,
> while (h) {
> int count = (h > 2047) ? 2047 : h;
>
> - if (nouveau_pushbuf_space(push, 16, 4, 0) ||
> + if (nouveau_pushbuf_space(push, 18, 4, 0) ||
> nouveau_pushbuf_refn (push, refs, 2))
> return;
>
> @@ -307,6 +307,10 @@ nv04_surface_copy_m2mf(struct gl_context *ctx,
> PUSH_DATA (push, count);
> PUSH_DATA (push, 0x0101);
> PUSH_DATA (push, 0);
> + BEGIN_NV04(push, NV04_GRAPH(M2MF, NOP), 1);
> + PUSH_DATA (push, 0);
> + BEGIN_NV04(push, NV03_M2MF(OFFSET_OUT), 1);
> + PUSH_DATA (push, 0);
>
> src_offset += src->pitch * count;
> dst_offset += dst->pitch * count;
> @@ -400,6 +404,17 @@ nv04_surface_copy(struct gl_context *ctx,
> int dx, int dy, int sx, int sy,
> int w, int h)
> {
> + bool compressed = _mesa_is_format_compressed(src->format);
> +
> + if (compressed) {
> + sx = nouveau_format_get_nblocksx(src->format, sx);
> + sy = nouveau_format_get_nblocksy(src->format, sy);
> + dx = nouveau_format_get_nblocksx(dst->format, sx);
> + dy = nouveau_format_get_nblocksy(dst->format, sy);
> + w = nouveau_format_get_nblocksx(src->format, w);
> + h = nouveau_format_get_nblocksy(src->format, h);
> + }
> +
> /* Linear texture copy. */
> if ((src->layout == LINEAR && dst->layout == LINEAR) ||
> dst->width <= 2 || dst->height <= 1) {
> diff --git a/src/mesa/drivers/dri/nouveau/nv20_context.c b/src/mesa/drivers/dri/nouveau/nv20_context.c
> index c911717..5a36c87 100644
> --- a/src/mesa/drivers/dri/nouveau/nv20_context.c
> +++ b/src/mesa/drivers/dri/nouveau/nv20_context.c
> @@ -460,6 +460,10 @@ nv20_context_create(struct nouveau_screen *screen, const struct gl_config *visua
> ctx->Extensions.ARB_texture_env_dot3 = true;
> ctx->Extensions.NV_fog_distance = true;
> ctx->Extensions.NV_texture_rectangle = true;
> + if (ctx->Mesa_DXTn) {
> + ctx->Extensions.EXT_texture_compression_s3tc = true;
> + ctx->Extensions.S3_s3tc = true;
> + }
>
> /* GL constants. */
> ctx->Const.MaxTextureCoordUnits = NV20_TEXTURE_UNITS;
> diff --git a/src/mesa/drivers/dri/nouveau/nv20_state_tex.c b/src/mesa/drivers/dri/nouveau/nv20_state_tex.c
> index 799510d..d8bfdf2 100644
> --- a/src/mesa/drivers/dri/nouveau/nv20_state_tex.c
> +++ b/src/mesa/drivers/dri/nouveau/nv20_state_tex.c
> @@ -108,6 +108,16 @@ get_tex_format_pot(struct gl_texture_image *ti)
> case MESA_FORMAT_L8:
> return NV20_3D_TEX_FORMAT_FORMAT_L8;
>
> + case MESA_FORMAT_RGB_DXT1:
> + case MESA_FORMAT_RGBA_DXT1:
> + return NV20_3D_TEX_FORMAT_FORMAT_DXT1;
> +
> + case MESA_FORMAT_RGBA_DXT3:
> + return NV20_3D_TEX_FORMAT_FORMAT_DXT3;
> +
> + case MESA_FORMAT_RGBA_DXT5:
> + return NV20_3D_TEX_FORMAT_FORMAT_DXT5;
> +
> default:
> assert(0);
> }
More information about the Nouveau
mailing list