#include "nouveau_driver.h"
#include "nouveau_context.h"
#include "nouveau_texture.h"
+#include "nouveau_fbo.h"
#include "nouveau_util.h"
+#include "main/pbo.h"
#include "main/texobj.h"
#include "main/texstore.h"
#include "main/texformat.h"
#include "main/texcompress.h"
#include "main/texgetimage.h"
#include "main/mipmap.h"
-#include "main/texfetch.h"
+#include "main/teximage.h"
+#include "drivers/common/meta.h"
+#include "swrast/s_texfetch.h"
static struct gl_texture_object *
-nouveau_texture_new(GLcontext *ctx, GLuint name, GLenum target)
+nouveau_texture_new(struct gl_context *ctx, GLuint name, GLenum target)
{
struct nouveau_texture *nt = CALLOC_STRUCT(nouveau_texture);
- _mesa_initialize_texture_object(&nt->base, name, target);
+ _mesa_initialize_texture_object(ctx, &nt->base, name, target);
return &nt->base;
}
static void
-nouveau_texture_free(GLcontext *ctx, struct gl_texture_object *t)
+nouveau_texture_free(struct gl_context *ctx, struct gl_texture_object *t)
{
struct nouveau_texture *nt = to_nouveau_texture(t);
int i;
}
static struct gl_texture_image *
-nouveau_teximage_new(GLcontext *ctx)
+nouveau_teximage_new(struct gl_context *ctx)
{
struct nouveau_teximage *nti = CALLOC_STRUCT(nouveau_teximage);
- return &nti->base;
+ return &nti->base.Base;
}
static void
-nouveau_teximage_free(GLcontext *ctx, struct gl_texture_image *ti)
+nouveau_teximage_free(struct gl_context *ctx, struct gl_texture_image *ti)
{
struct nouveau_teximage *nti = to_nouveau_teximage(ti);
}
static void
-nouveau_teximage_map(GLcontext *ctx, struct gl_texture_image *ti)
+nouveau_map_texture_image(struct gl_context *ctx,
+ struct gl_texture_image *ti,
+ GLuint slice,
+ GLuint x, GLuint y, GLuint w, GLuint h,
+ GLbitfield mode,
+ GLubyte **map,
+ GLint *stride)
{
- struct nouveau_surface *s = &to_nouveau_teximage(ti)->surface;
- int ret;
-
- ret = nouveau_bo_map(s->bo, NOUVEAU_BO_RDWR);
- assert(!ret);
-
- ti->Data = s->bo->map;
+ struct nouveau_teximage *nti = to_nouveau_teximage(ti);
+ struct nouveau_surface *s = &nti->surface;
+ struct nouveau_surface *st = &nti->transfer.surface;
+ struct nouveau_client *client = context_client(ctx);
+
+ /* Nouveau has no support for 3D or cubemap textures. */
+ assert(slice == 0);
+
+ 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.
+ */
+ st->layout = LINEAR;
+ st->format = s->format;
+ st->cpp = s->cpp;
+ st->width = w;
+ st->height = h;
+ st->pitch = s->pitch;
+ nti->transfer.x = x;
+ nti->transfer.y = y;
+
+ size = get_format_blocksy(st->format, h) * st->pitch;
+ *map = nouveau_get_scratch(ctx, size,
+ &st->bo, &st->offset);
+ *stride = st->pitch;
+ } else {
+ int ret, flags = 0;
+
+ if (mode & GL_MAP_READ_BIT)
+ flags |= NOUVEAU_BO_RD;
+ if (mode & GL_MAP_WRITE_BIT)
+ flags |= NOUVEAU_BO_WR;
+
+ if (!s->bo->map) {
+ ret = nouveau_bo_map(s->bo, flags, client);
+ assert(!ret);
+ }
+
+ *map = s->bo->map +
+ get_format_blocksy(s->format, y) * s->pitch +
+ get_format_blocksx(s->format, x) * s->cpp;
+ *stride = s->pitch;
+ }
+ } else {
+ *map = nti->base.Buffer +
+ get_format_blocksy(s->format, y) * s->pitch +
+ get_format_blocksx(s->format, x) * s->cpp;
+ *stride = s->pitch;
+ }
}
static void
-nouveau_teximage_unmap(GLcontext *ctx, struct gl_texture_image *ti)
+nouveau_unmap_texture_image(struct gl_context *ctx, struct gl_texture_image *ti,
+ GLuint slice)
{
- struct nouveau_surface *s = &to_nouveau_teximage(ti)->surface;
+ struct nouveau_teximage *nti = to_nouveau_teximage(ti);
+ struct nouveau_surface *s = &nti->surface;
+ struct nouveau_surface *st = &nti->transfer.surface;
- nouveau_bo_unmap(s->bo);
- ti->Data = NULL;
+ if (st->bo) {
+ context_drv(ctx)->surface_copy(ctx, s, st, nti->transfer.x,
+ nti->transfer.y, 0, 0,
+ st->width, st->height);
+ nouveau_surface_ref(NULL, st);
+
+ }
}
-static gl_format
-nouveau_choose_tex_format(GLcontext *ctx, GLint internalFormat,
+static mesa_format
+nouveau_choose_tex_format(struct gl_context *ctx, GLenum target,
+ GLint internalFormat,
GLenum srcFormat, GLenum srcType)
{
switch (internalFormat) {
case 4:
case GL_RGBA:
- case GL_RGB10_A2:
+ case GL_RGBA2:
+ case GL_RGBA4:
+ case GL_RGBA8:
case GL_RGBA12:
case GL_RGBA16:
- case GL_RGBA8:
+ case GL_RGB10_A2:
+ case GL_COMPRESSED_RGBA:
+ return MESA_FORMAT_B8G8R8A8_UNORM;
+ case GL_RGB5_A1:
+ return MESA_FORMAT_B5G5R5A1_UNORM;
+
case GL_RGB:
case GL_RGB8:
case GL_RGB10:
case GL_RGB12:
case GL_RGB16:
- return MESA_FORMAT_ARGB8888;
- case GL_RGB5_A1:
- return MESA_FORMAT_ARGB1555;
- case GL_RGBA2:
- case GL_RGBA4:
- return MESA_FORMAT_ARGB4444;
-
+ case GL_COMPRESSED_RGB:
+ return MESA_FORMAT_B8G8R8X8_UNORM;
case 3:
case GL_R3_G3_B2:
case GL_RGB4:
case GL_RGB5:
- return MESA_FORMAT_RGB565;
-
- case GL_ALPHA:
- case GL_ALPHA4:
- case GL_ALPHA12:
- case GL_ALPHA16:
- case GL_ALPHA8:
- return MESA_FORMAT_A8;
-
- case 1:
- case GL_LUMINANCE:
- case GL_LUMINANCE4:
- case GL_LUMINANCE12:
- case GL_LUMINANCE16:
- case GL_LUMINANCE8:
- return MESA_FORMAT_L8;
+ return MESA_FORMAT_B5G6R5_UNORM;
case 2:
case GL_LUMINANCE_ALPHA:
case GL_LUMINANCE12_ALPHA12:
case GL_LUMINANCE16_ALPHA16:
case GL_LUMINANCE8_ALPHA8:
- return MESA_FORMAT_ARGB8888;
+ case GL_COMPRESSED_LUMINANCE_ALPHA:
+ return MESA_FORMAT_B8G8R8A8_UNORM;
+
+ case 1:
+ case GL_LUMINANCE:
+ case GL_LUMINANCE4:
+ case GL_LUMINANCE12:
+ case GL_LUMINANCE16:
+ case GL_LUMINANCE8:
+ case GL_COMPRESSED_LUMINANCE:
+ return MESA_FORMAT_L_UNORM8;
+
+ case GL_ALPHA:
+ case GL_ALPHA4:
+ case GL_ALPHA12:
+ case GL_ALPHA16:
+ case GL_ALPHA8:
+ case GL_COMPRESSED_ALPHA:
+ return MESA_FORMAT_A_UNORM8;
case GL_INTENSITY:
case GL_INTENSITY4:
case GL_INTENSITY12:
case GL_INTENSITY16:
case GL_INTENSITY8:
- return MESA_FORMAT_ARGB8888;
+ case GL_COMPRESSED_INTENSITY:
+ return MESA_FORMAT_I_UNORM8;
+
+ 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_COLOR_INDEX:
- case GL_COLOR_INDEX1_EXT:
- case GL_COLOR_INDEX2_EXT:
- case GL_COLOR_INDEX4_EXT:
- case GL_COLOR_INDEX12_EXT:
- case GL_COLOR_INDEX16_EXT:
- case GL_COLOR_INDEX8_EXT:
- return MESA_FORMAT_CI8;
+ case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
+ return MESA_FORMAT_RGBA_DXT5;
default:
assert(0);
}
}
-static void
-nouveau_teximage(GLcontext *ctx, GLint dims, GLenum target, GLint level,
- GLint internalFormat,
- GLint width, GLint height, GLint depth, GLint border,
- GLenum format, GLenum type, const GLvoid *pixels,
- const struct gl_pixelstore_attrib *packing,
- struct gl_texture_object *t,
- struct gl_texture_image *ti)
+static GLboolean
+teximage_fits(struct gl_texture_object *t, int level)
{
- struct nouveau_surface *s = &to_nouveau_teximage(ti)->surface;
- unsigned bo_flags = NOUVEAU_BO_GART | NOUVEAU_BO_RDWR | NOUVEAU_BO_MAP;
- int ret;
+ struct nouveau_surface *s = &to_nouveau_texture(t)->surfaces[level];
+ struct gl_texture_image *ti = t->Image[0][level];
- /* Allocate a new bo for the image. */
- nouveau_surface_alloc(ctx, s, LINEAR, bo_flags, ti->TexFormat,
- width, height);
- ti->RowStride = s->pitch / s->cpp;
-
- pixels = _mesa_validate_pbo_teximage(ctx, dims, width, height, depth,
- format, type, pixels, packing,
- "glTexImage");
- if (!pixels)
- return;
-
- /* Store the pixel data. */
- nouveau_teximage_map(ctx, ti);
-
- ret = _mesa_texstore(ctx, dims, ti->_BaseFormat,
- ti->TexFormat, ti->Data,
- 0, 0, 0, s->pitch,
- ti->ImageOffsets,
- width, height, depth,
- format, type, pixels, packing);
- assert(ret);
-
- nouveau_teximage_unmap(ctx, ti);
- _mesa_unmap_teximage_pbo(ctx, packing);
+ if (!ti || !to_nouveau_teximage(ti)->surface.bo)
+ return GL_FALSE;
- context_dirty_i(ctx, TEX_OBJ, ctx->Texture.CurrentUnit);
- context_dirty_i(ctx, TEX_ENV, ctx->Texture.CurrentUnit);
- texture_dirty(t);
+ if (level == t->BaseLevel && (s->offset & 0x7f))
+ return GL_FALSE;
+
+ return t->Target == GL_TEXTURE_RECTANGLE ||
+ (s->bo && s->format == ti->TexFormat &&
+ s->width == ti->Width && s->height == ti->Height);
}
-static void
-nouveau_teximage_1d(GLcontext *ctx, GLenum target, GLint level,
- GLint internalFormat,
- GLint width, GLint border,
- GLenum format, GLenum type, const GLvoid *pixels,
- const struct gl_pixelstore_attrib *packing,
- struct gl_texture_object *t,
- struct gl_texture_image *ti)
+static GLboolean
+validate_teximage(struct gl_context *ctx, struct gl_texture_object *t,
+ int level, int x, int y, int z,
+ int width, int height, int depth)
{
- nouveau_teximage(ctx, 1, target, level, internalFormat,
- width, 1, 1, border, format, type, pixels,
- packing, t, ti);
+ struct gl_texture_image *ti = t->Image[0][level];
+
+ if (teximage_fits(t, level)) {
+ struct nouveau_surface *ss = to_nouveau_texture(t)->surfaces;
+ struct nouveau_surface *s = &to_nouveau_teximage(ti)->surface;
+
+ if (t->Target == GL_TEXTURE_RECTANGLE)
+ nouveau_surface_ref(s, &ss[level]);
+ else
+ context_drv(ctx)->surface_copy(ctx, &ss[level], s,
+ x, y, x, y,
+ width, height);
+
+ return GL_TRUE;
+ }
+
+ return GL_FALSE;
}
-static void
-nouveau_teximage_2d(GLcontext *ctx, GLenum target, GLint level,
- GLint internalFormat,
- GLint width, GLint height, GLint border,
- GLenum format, GLenum type, const GLvoid *pixels,
- const struct gl_pixelstore_attrib *packing,
- struct gl_texture_object *t,
- struct gl_texture_image *ti)
+static int
+get_last_level(struct gl_texture_object *t)
{
- nouveau_teximage(ctx, 2, target, level, internalFormat,
- width, height, 1, border, format, type, pixels,
- packing, t, ti);
+ struct gl_texture_image *base = t->Image[0][t->BaseLevel];
+
+ if (t->Sampler.MinFilter == GL_NEAREST ||
+ t->Sampler.MinFilter == GL_LINEAR || !base)
+ return t->BaseLevel;
+ else
+ return MIN2(t->BaseLevel + base->MaxNumLevels - 1, t->MaxLevel);
}
static void
-nouveau_teximage_3d(GLcontext *ctx, GLenum target, GLint level,
- GLint internalFormat,
- GLint width, GLint height, GLint depth, GLint border,
- GLenum format, GLenum type, const GLvoid *pixels,
- const struct gl_pixelstore_attrib *packing,
- struct gl_texture_object *t,
- struct gl_texture_image *ti)
+relayout_texture(struct gl_context *ctx, struct gl_texture_object *t)
{
- nouveau_teximage(ctx, 3, target, level, internalFormat,
- width, height, depth, border, format, type, pixels,
- packing, t, ti);
+ struct gl_texture_image *base = t->Image[0][t->BaseLevel];
+
+ if (base && t->Target != GL_TEXTURE_RECTANGLE) {
+ 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);
+ enum nouveau_surface_layout layout =
+ (_mesa_is_format_compressed(s->format) ? LINEAR : SWIZZLED);
+ unsigned size, pitch, offset = 0,
+ width = s->width,
+ height = s->height;
+
+ /* Deallocate the old storage. */
+ for (i = 0; i < MAX_TEXTURE_LEVELS; i++)
+ nouveau_bo_ref(NULL, &ss[i].bo);
+
+ /* Relayout the mipmap tree. */
+ for (i = t->BaseLevel; i <= last; i++) {
+ pitch = _mesa_format_row_stride(s->format, width);
+ size = get_format_blocksy(s->format, height) * pitch;
+
+ /* Images larger than 16B have to be aligned. */
+ if (size > 16)
+ offset = align(offset, 64);
+
+ ss[i] = (struct nouveau_surface) {
+ .offset = offset,
+ .layout = layout,
+ .format = s->format,
+ .width = width,
+ .height = height,
+ .cpp = s->cpp,
+ .pitch = pitch,
+ };
+
+ offset += size;
+ width = minify(width, 1);
+ height = minify(height, 1);
+ }
+
+ if (t->BaseLevel <= last) {
+ /* Get new storage. */
+ size = align(offset, 64);
+ assert(size);
+
+ ret = nouveau_bo_new(context_dev(ctx), NOUVEAU_BO_MAP |
+ NOUVEAU_BO_GART | NOUVEAU_BO_VRAM,
+ 0, size, NULL, &ss[last].bo);
+ assert(!ret);
+
+ for (i = t->BaseLevel; i < last; i++)
+ nouveau_bo_ref(ss[last].bo, &ss[i].bo);
+ }
+ }
}
-static void
-nouveau_texsubimage_3d(GLcontext *ctx, GLenum target, GLint level,
- GLint xoffset, GLint yoffset, GLint zoffset,
- GLint width, GLint height, GLint depth,
- GLenum format, GLenum type, const void *pixels,
- const struct gl_pixelstore_attrib *packing,
- struct gl_texture_object *t,
- struct gl_texture_image *ti)
+GLboolean
+nouveau_texture_validate(struct gl_context *ctx, struct gl_texture_object *t)
{
- nouveau_teximage_map(ctx, ti);
- _mesa_store_texsubimage3d(ctx, target, level, xoffset, yoffset, zoffset,
- width, height, depth, format, type, pixels,
- packing, t, ti);
- nouveau_teximage_unmap(ctx, ti);
+ struct nouveau_texture *nt = to_nouveau_texture(t);
+ int i, last = get_last_level(t);
- context_dirty_i(ctx, TEX_OBJ, ctx->Texture.CurrentUnit);
- texture_dirty(t);
-}
+ if (!teximage_fits(t, t->BaseLevel) ||
+ !teximage_fits(t, last))
+ return GL_FALSE;
-static void
-nouveau_texsubimage_2d(GLcontext *ctx, GLenum target, GLint level,
- GLint xoffset, GLint yoffset,
- GLint width, GLint height,
- GLenum format, GLenum type, const void *pixels,
- const struct gl_pixelstore_attrib *packing,
- struct gl_texture_object *t,
- struct gl_texture_image *ti)
-{
- nouveau_teximage_map(ctx, ti);
- _mesa_store_texsubimage2d(ctx, target, level, xoffset, yoffset,
- width, height, format, type, pixels,
- packing, t, ti);
- nouveau_teximage_unmap(ctx, ti);
+ if (nt->dirty) {
+ nt->dirty = GL_FALSE;
- context_dirty_i(ctx, TEX_OBJ, ctx->Texture.CurrentUnit);
- texture_dirty(t);
+ /* Copy the teximages to the actual miptree. */
+ for (i = t->BaseLevel; i <= last; i++) {
+ struct nouveau_surface *s = &nt->surfaces[i];
+
+ validate_teximage(ctx, t, i, 0, 0, 0,
+ s->width, s->height, 1);
+ }
+
+ PUSH_KICK(context_push(ctx));
+ }
+
+ return GL_TRUE;
}
-static void
-nouveau_texsubimage_1d(GLcontext *ctx, GLenum target, GLint level,
- GLint xoffset, GLint width,
- GLenum format, GLenum type, const void *pixels,
- const struct gl_pixelstore_attrib *packing,
- struct gl_texture_object *t,
- struct gl_texture_image *ti)
+void
+nouveau_texture_reallocate(struct gl_context *ctx, struct gl_texture_object *t)
{
- nouveau_teximage_map(ctx, ti);
- _mesa_store_texsubimage1d(ctx, target, level, xoffset,
- width, format, type, pixels,
- packing, t, ti);
- nouveau_teximage_unmap(ctx, ti);
+ if (!teximage_fits(t, t->BaseLevel) ||
+ !teximage_fits(t, get_last_level(t))) {
+ texture_dirty(t);
+ relayout_texture(ctx, t);
+ nouveau_texture_validate(ctx, t);
+ }
+}
- context_dirty_i(ctx, TEX_OBJ, ctx->Texture.CurrentUnit);
- texture_dirty(t);
+static unsigned
+get_teximage_placement(struct gl_texture_image *ti)
+{
+ if (ti->TexFormat == MESA_FORMAT_A_UNORM8 ||
+ ti->TexFormat == MESA_FORMAT_L_UNORM8 ||
+ ti->TexFormat == MESA_FORMAT_I_UNORM8)
+ /* 1 cpp formats will have to be swizzled by the CPU,
+ * so leave them in system RAM for now. */
+ return NOUVEAU_BO_MAP;
+ else
+ return NOUVEAU_BO_GART | NOUVEAU_BO_MAP;
}
static void
-nouveau_get_teximage(GLcontext *ctx, GLenum target, GLint level,
- GLenum format, GLenum type, GLvoid *pixels,
- struct gl_texture_object *t,
- struct gl_texture_image *ti)
+nouveau_compressed_copy(struct gl_context *ctx, GLint dims,
+ struct gl_texture_image *ti,
+ GLsizei width, GLsizei height, GLsizei depth,
+ const GLvoid *src, GLvoid *dst, int row_stride)
{
- nouveau_teximage_map(ctx, ti);
- _mesa_get_teximage(ctx, target, level, format, type, pixels,
- t, ti);
- nouveau_teximage_unmap(ctx, ti);
+ struct compressed_pixelstore store;
+ int i;
+
+ _mesa_compute_compressed_pixelstore(dims, ti->TexFormat,
+ width, height, depth,
+ &ctx->Unpack, &store);
+
+ src += store.SkipBytes;
+
+ assert(store.CopySlices == 1);
+
+ /* copy rows of blocks */
+ for (i = 0; i < store.CopyRowsPerSlice; i++) {
+ memcpy(dst, src, store.CopyBytesPerRow);
+ dst += row_stride;
+ src += store.TotalBytesPerRow;
+ }
}
static void
-nouveau_bind_texture(GLcontext *ctx, GLenum target,
- struct gl_texture_object *t)
+nouveau_teximage(struct gl_context *ctx, GLint dims,
+ struct gl_texture_image *ti,
+ GLsizei imageSize,
+ GLenum format, GLenum type, const GLvoid *pixels,
+ const struct gl_pixelstore_attrib *packing,
+ GLboolean compressed)
{
+ struct gl_texture_object *t = ti->TexObject;
+ const GLuint level = ti->Level;
+ struct nouveau_surface *s = &to_nouveau_teximage(ti)->surface;
+ struct nouveau_teximage *nti = to_nouveau_teximage(ti);
+ int ret;
+ GLuint depth = compressed ? 1 : ti->Depth;
+
+ /* Allocate a new bo for the image. */
+ nouveau_surface_alloc(ctx, s, LINEAR, get_teximage_placement(ti),
+ ti->TexFormat, ti->Width, ti->Height);
+ nti->base.RowStride = s->pitch / s->cpp;
+
+ if (compressed)
+ pixels = _mesa_validate_pbo_compressed_teximage(ctx,
+ dims, imageSize,
+ pixels, packing, "glCompressedTexImage");
+ else
+ pixels = _mesa_validate_pbo_teximage(ctx,
+ dims, ti->Width, ti->Height, depth, format, type,
+ pixels, packing, "glTexImage");
+
+ if (pixels) {
+ GLubyte *map;
+ int row_stride;
+
+ /* Store the pixel data. */
+ nouveau_map_texture_image(ctx, ti, 0,
+ 0, 0, ti->Width, ti->Height,
+ GL_MAP_WRITE_BIT,
+ &map, &row_stride);
+
+ if (compressed) {
+ nouveau_compressed_copy(ctx, dims, ti,
+ ti->Width, ti->Height, depth,
+ pixels, map, row_stride);
+ } else {
+ ret = _mesa_texstore(ctx, dims, ti->_BaseFormat,
+ ti->TexFormat,
+ row_stride,
+ &map,
+ ti->Width, ti->Height, depth,
+ format, type, pixels, packing);
+ assert(ret);
+ }
+
+ nouveau_unmap_texture_image(ctx, ti, 0);
+ _mesa_unmap_teximage_pbo(ctx, packing);
+
+ if (!validate_teximage(ctx, t, level, 0, 0, 0,
+ ti->Width, ti->Height, depth))
+ /* It doesn't fit, mark it as dirty. */
+ texture_dirty(t);
+ }
+
+ if (level == t->BaseLevel) {
+ if (!teximage_fits(t, level))
+ relayout_texture(ctx, t);
+ nouveau_texture_validate(ctx, t);
+ }
+
context_dirty_i(ctx, TEX_OBJ, ctx->Texture.CurrentUnit);
context_dirty_i(ctx, TEX_ENV, ctx->Texture.CurrentUnit);
}
+
static void
-nouveau_texture_map(GLcontext *ctx, struct gl_texture_object *t)
+nouveau_teximage_123d(struct gl_context *ctx, GLuint dims,
+ struct gl_texture_image *ti,
+ GLenum format, GLenum type, const GLvoid *pixels,
+ const struct gl_pixelstore_attrib *packing)
{
- int i;
-
- for (i = t->BaseLevel; i < t->_MaxLevel; i++) {
- if (t->Image[0][i])
- nouveau_teximage_map(ctx, t->Image[0][i]);
- }
+ nouveau_teximage(ctx, dims, ti, 0, format, type, pixels,
+ packing, GL_FALSE);
}
static void
-nouveau_texture_unmap(GLcontext *ctx, struct gl_texture_object *t)
+nouveau_compressed_teximage(struct gl_context *ctx, GLuint dims,
+ struct gl_texture_image *ti,
+ GLsizei imageSize, const GLvoid *data)
{
- int i;
+ nouveau_teximage(ctx, 2, ti, imageSize, 0, 0, data,
+ &ctx->Unpack, GL_TRUE);
+}
- for (i = t->BaseLevel; i < t->_MaxLevel; i++) {
- if (t->Image[0][i])
- nouveau_teximage_unmap(ctx, t->Image[0][i]);
- }
+static GLboolean
+nouveau_teximage_alloc(struct gl_context *ctx, struct gl_texture_image *ti)
+{
+ nouveau_teximage(ctx, 3, ti, 0, 0, 0, NULL,
+ &ctx->DefaultPacking,
+ _mesa_is_format_compressed(ti->TexFormat));
+ return GL_TRUE;
}
static void
-relayout_miptree(GLcontext *ctx, struct gl_texture_object *t)
+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,
+ GLboolean compressed)
{
- struct nouveau_surface *ss = to_nouveau_texture(t)->surfaces;
- unsigned last_level, offset = 0;
- unsigned size;
- int i, ret;
-
- if (t->MinFilter == GL_NEAREST ||
- t->MinFilter == GL_LINEAR)
- last_level = t->BaseLevel;
- else
- last_level = t->_MaxLevel;
+ int ret;
- /* Deallocate the old storage. */
- for (i = 0; i < MAX_TEXTURE_LEVELS; i++)
- nouveau_bo_ref(NULL, &ss[i].bo);
-
- /* Relayout the mipmap tree. */
- for (i = t->BaseLevel; i <= last_level; i++) {
- struct nouveau_surface *s =
- &to_nouveau_teximage(t->Image[0][i])->surface;
-
- size = s->width * s->height * s->cpp;
-
- /* Images larger than 16B have to be aligned. */
- if (size > 16)
- offset = align(offset, 64);
-
- ss[i] = (struct nouveau_surface) {
- .offset = offset,
- .layout = SWIZZLED,
- .format = s->format,
- .width = s->width,
- .height = s->height,
- .cpp = s->cpp,
- .pitch = s->width * s->cpp,
- };
-
- offset += size;
+ if (compressed)
+ pixels = _mesa_validate_pbo_compressed_teximage(ctx,
+ dims, imageSize,
+ pixels, packing, "glCompressedTexSubImage");
+ else
+ pixels = _mesa_validate_pbo_teximage(ctx,
+ dims, width, height, depth, format, type,
+ pixels, packing, "glTexSubImage");
+
+ if (pixels) {
+ GLubyte *map;
+ int row_stride;
+
+ nouveau_map_texture_image(ctx, ti, 0,
+ xoffset, yoffset, width, height,
+ GL_MAP_WRITE_BIT, &map, &row_stride);
+
+ if (compressed) {
+ nouveau_compressed_copy(ctx, dims, ti,
+ width, height, depth,
+ pixels, map, row_stride);
+ } else {
+ ret = _mesa_texstore(ctx, dims, ti->_BaseFormat,
+ ti->TexFormat,
+ row_stride, &map,
+ width, height, depth,
+ format, type, pixels, packing);
+ assert(ret);
+ }
+
+ nouveau_unmap_texture_image(ctx, ti, 0);
+ _mesa_unmap_teximage_pbo(ctx, packing);
}
- /* Get new storage. */
- size = align(offset, 64);
-
- ret = nouveau_bo_new(context_dev(ctx),
- NOUVEAU_BO_GART | NOUVEAU_BO_VRAM,
- 0, size, &ss[last_level].bo);
- assert(!ret);
+ if (!to_nouveau_texture(ti->TexObject)->dirty)
+ validate_teximage(ctx, ti->TexObject, ti->Level,
+ xoffset, yoffset, zoffset,
+ width, height, depth);
+}
- for (i = t->BaseLevel; i < last_level; i++)
- nouveau_bo_ref(ss[last_level].bo, &ss[i].bo);
+static void
+nouveau_texsubimage_123d(struct gl_context *ctx, GLuint dims,
+ struct gl_texture_image *ti,
+ GLint xoffset, GLint yoffset, GLint zoffset,
+ GLint width, GLint height, GLint depth,
+ GLenum format, GLenum type, const void *pixels,
+ const struct gl_pixelstore_attrib *packing)
+{
+ nouveau_texsubimage(ctx, dims, ti, xoffset, yoffset, zoffset,
+ width, height, depth, 0, format, type, pixels,
+ packing, GL_FALSE);
}
-void
-nouveau_texture_validate(GLcontext *ctx, struct gl_texture_object *t)
+static void
+nouveau_compressed_texsubimage(struct gl_context *ctx, GLuint dims,
+ struct gl_texture_image *ti,
+ GLint xoffset, GLint yoffset, GLint zoffset,
+ GLsizei width, GLint height, GLint depth,
+ GLenum format,
+ GLint imageSize, const void *data)
{
- struct nouveau_texture *nt = to_nouveau_texture(t);
- int i;
+ nouveau_texsubimage(ctx, dims, ti, xoffset, yoffset, zoffset,
+ width, height, depth, imageSize, format, 0, data,
+ &ctx->Unpack, GL_TRUE);
+}
- if (!nt->dirty)
- return;
+static void
+nouveau_bind_texture(struct gl_context *ctx, GLuint texUnit,
+ GLenum target, struct gl_texture_object *t)
+{
+ context_dirty_i(ctx, TEX_OBJ, texUnit);
+ context_dirty_i(ctx, TEX_ENV, texUnit);
+}
- nt->dirty = GL_FALSE;
+static mesa_format
+get_texbuffer_format(struct gl_renderbuffer *rb, GLint format)
+{
+ struct nouveau_surface *s = &to_nouveau_renderbuffer(rb)->surface;
- relayout_miptree(ctx, t);
+ if (s->cpp < 4)
+ return s->format;
+ else if (format == __DRI_TEXTURE_FORMAT_RGBA)
+ return MESA_FORMAT_B8G8R8A8_UNORM;
+ else
+ return MESA_FORMAT_B8G8R8X8_UNORM;
+}
- /* Copy the teximages to the actual swizzled miptree. */
- for (i = t->BaseLevel; i < MAX_TEXTURE_LEVELS; i++) {
- struct gl_texture_image *ti = t->Image[0][i];
- struct nouveau_surface *s = &to_nouveau_teximage(ti)->surface;
+void
+nouveau_set_texbuffer(__DRIcontext *dri_ctx,
+ GLint target, GLint format,
+ __DRIdrawable *draw)
+{
+ struct nouveau_context *nctx = dri_ctx->driverPrivate;
+ struct gl_context *ctx = &nctx->base;
+ struct gl_framebuffer *fb = draw->driverPrivate;
+ struct gl_renderbuffer *rb =
+ fb->Attachment[BUFFER_FRONT_LEFT].Renderbuffer;
+ struct gl_texture_object *t = _mesa_get_current_tex_object(ctx, target);
+ struct gl_texture_image *ti;
+ struct nouveau_teximage *nti;
+ struct nouveau_surface *s;
+
+ _mesa_lock_texture(ctx, t);
+ ti = _mesa_get_tex_image(ctx, t, target, 0);
+ nti = to_nouveau_teximage(ti);
+ s = &to_nouveau_teximage(ti)->surface;
+
+ /* Update the texture surface with the given drawable. */
+ nouveau_update_renderbuffers(dri_ctx, draw);
+ nouveau_surface_ref(&to_nouveau_renderbuffer(rb)->surface, s);
+
+ s->format = get_texbuffer_format(rb, format);
+
+ /* Update the image fields. */
+ _mesa_init_teximage_fields(ctx, ti, s->width, s->height,
+ 1, 0, s->cpp, s->format);
+ nti->base.RowStride = s->pitch / s->cpp;
+
+ /* Try to validate it. */
+ if (!validate_teximage(ctx, t, 0, 0, 0, 0, s->width, s->height, 1))
+ nouveau_texture_reallocate(ctx, t);
- if (!nt->surfaces[i].bo)
- break;
+ context_dirty_i(ctx, TEX_OBJ, ctx->Texture.CurrentUnit);
+ context_dirty_i(ctx, TEX_ENV, ctx->Texture.CurrentUnit);
- context_drv(ctx)->surface_copy(ctx, &nt->surfaces[i], s,
- 0, 0, 0, 0,
- s->width, s->height);
- }
+ _mesa_unlock_texture(ctx, t);
}
void
functions->NewTextureObject = nouveau_texture_new;
functions->DeleteTexture = nouveau_texture_free;
functions->NewTextureImage = nouveau_teximage_new;
- functions->FreeTexImageData = nouveau_teximage_free;
+ functions->FreeTextureImageBuffer = nouveau_teximage_free;
+ functions->AllocTextureImageBuffer = nouveau_teximage_alloc;
functions->ChooseTextureFormat = nouveau_choose_tex_format;
- functions->TexImage1D = nouveau_teximage_1d;
- functions->TexImage2D = nouveau_teximage_2d;
- functions->TexImage3D = nouveau_teximage_3d;
- functions->TexSubImage1D = nouveau_texsubimage_1d;
- functions->TexSubImage2D = nouveau_texsubimage_2d;
- functions->TexSubImage3D = nouveau_texsubimage_3d;
- functions->GetTexImage = nouveau_get_teximage;
+ functions->TexImage = nouveau_teximage_123d;
+ functions->TexSubImage = nouveau_texsubimage_123d;
+ functions->CompressedTexImage = nouveau_compressed_teximage;
+ functions->CompressedTexSubImage = nouveau_compressed_texsubimage;
functions->BindTexture = nouveau_bind_texture;
- functions->MapTexture = nouveau_texture_map;
- functions->UnmapTexture = nouveau_texture_unmap;
+ functions->MapTextureImage = nouveau_map_texture_image;
+ functions->UnmapTextureImage = nouveau_unmap_texture_image;
}