| /* |
| * Copyright (C) 2009 Francisco Jerez. |
| * All Rights Reserved. |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining |
| * a copy of this software and associated documentation files (the |
| * "Software"), to deal in the Software without restriction, including |
| * without limitation the rights to use, copy, modify, merge, publish, |
| * distribute, sublicense, and/or sell copies of the Software, and to |
| * permit persons to whom the Software is furnished to do so, subject to |
| * the following conditions: |
| * |
| * The above copyright notice and this permission notice (including the |
| * next paragraph) shall be included in all copies or substantial |
| * portions of the Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
| * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. |
| * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE |
| * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
| * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
| * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| * |
| */ |
| |
| #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/teximage.h" |
| #include "drivers/common/meta.h" |
| #include "swrast/s_texfetch.h" |
| |
| static struct gl_texture_object * |
| nouveau_texture_new(struct gl_context *ctx, GLuint name, GLenum target) |
| { |
| struct nouveau_texture *nt = CALLOC_STRUCT(nouveau_texture); |
| |
| _mesa_initialize_texture_object(ctx, &nt->base, name, target); |
| |
| return &nt->base; |
| } |
| |
| static void |
| nouveau_texture_free(struct gl_context *ctx, struct gl_texture_object *t) |
| { |
| struct nouveau_texture *nt = to_nouveau_texture(t); |
| int i; |
| |
| for (i = 0; i < MAX_TEXTURE_LEVELS; i++) |
| nouveau_surface_ref(NULL, &nt->surfaces[i]); |
| |
| _mesa_delete_texture_object(ctx, t); |
| } |
| |
| static struct gl_texture_image * |
| nouveau_teximage_new(struct gl_context *ctx) |
| { |
| struct nouveau_teximage *nti = CALLOC_STRUCT(nouveau_teximage); |
| |
| return &nti->base.Base; |
| } |
| |
| static void |
| nouveau_teximage_free(struct gl_context *ctx, struct gl_texture_image *ti) |
| { |
| struct nouveau_teximage *nti = to_nouveau_teximage(ti); |
| |
| nouveau_surface_ref(NULL, &nti->surface); |
| } |
| |
| static void |
| 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_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_unmap_texture_image(struct gl_context *ctx, struct gl_texture_image *ti, |
| GLuint slice) |
| { |
| struct nouveau_teximage *nti = to_nouveau_teximage(ti); |
| struct nouveau_surface *s = &nti->surface; |
| struct nouveau_surface *st = &nti->transfer.surface; |
| |
| 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 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_RGBA2: |
| case GL_RGBA4: |
| case GL_RGBA8: |
| case GL_RGBA12: |
| case GL_RGBA16: |
| 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: |
| 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_B5G6R5_UNORM; |
| |
| case 2: |
| case GL_LUMINANCE_ALPHA: |
| case GL_LUMINANCE4_ALPHA4: |
| case GL_LUMINANCE6_ALPHA2: |
| case GL_LUMINANCE12_ALPHA4: |
| case GL_LUMINANCE12_ALPHA12: |
| case GL_LUMINANCE16_ALPHA16: |
| case GL_LUMINANCE8_ALPHA8: |
| 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: |
| 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_COMPRESSED_RGBA_S3TC_DXT5_EXT: |
| return MESA_FORMAT_RGBA_DXT5; |
| |
| default: |
| assert(0); |
| } |
| } |
| |
| static GLboolean |
| teximage_fits(struct gl_texture_object *t, int level) |
| { |
| struct nouveau_surface *s = &to_nouveau_texture(t)->surfaces[level]; |
| struct gl_texture_image *ti = t->Image[0][level]; |
| |
| if (!ti || !to_nouveau_teximage(ti)->surface.bo) |
| return GL_FALSE; |
| |
| 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 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) |
| { |
| 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 int |
| get_last_level(struct gl_texture_object *t) |
| { |
| 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 |
| relayout_texture(struct gl_context *ctx, struct gl_texture_object *t) |
| { |
| 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); |
| } |
| } |
| } |
| |
| GLboolean |
| nouveau_texture_validate(struct gl_context *ctx, struct gl_texture_object *t) |
| { |
| struct nouveau_texture *nt = to_nouveau_texture(t); |
| int i, last = get_last_level(t); |
| |
| if (!teximage_fits(t, t->BaseLevel) || |
| !teximage_fits(t, last)) |
| return GL_FALSE; |
| |
| if (nt->dirty) { |
| nt->dirty = GL_FALSE; |
| |
| /* 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; |
| } |
| |
| void |
| nouveau_texture_reallocate(struct gl_context *ctx, struct gl_texture_object *t) |
| { |
| 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); |
| } |
| } |
| |
| 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_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) |
| { |
| 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_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_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) |
| { |
| nouveau_teximage(ctx, dims, ti, 0, format, type, pixels, |
| packing, GL_FALSE); |
| } |
| |
| static void |
| nouveau_compressed_teximage(struct gl_context *ctx, GLuint dims, |
| struct gl_texture_image *ti, |
| GLsizei imageSize, const GLvoid *data) |
| { |
| nouveau_teximage(ctx, 2, ti, imageSize, 0, 0, data, |
| &ctx->Unpack, GL_TRUE); |
| } |
| |
| 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 |
| 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) |
| { |
| int ret; |
| |
| 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); |
| } |
| |
| if (!to_nouveau_texture(ti->TexObject)->dirty) |
| validate_teximage(ctx, ti->TexObject, ti->Level, |
| xoffset, yoffset, zoffset, |
| width, height, depth); |
| } |
| |
| 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); |
| } |
| |
| 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) |
| { |
| nouveau_texsubimage(ctx, dims, ti, xoffset, yoffset, zoffset, |
| width, height, depth, imageSize, format, 0, data, |
| &ctx->Unpack, GL_TRUE); |
| } |
| |
| 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); |
| } |
| |
| static mesa_format |
| get_texbuffer_format(struct gl_renderbuffer *rb, GLint format) |
| { |
| struct nouveau_surface *s = &to_nouveau_renderbuffer(rb)->surface; |
| |
| 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; |
| } |
| |
| 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); |
| |
| context_dirty_i(ctx, TEX_OBJ, ctx->Texture.CurrentUnit); |
| context_dirty_i(ctx, TEX_ENV, ctx->Texture.CurrentUnit); |
| |
| _mesa_unlock_texture(ctx, t); |
| } |
| |
| void |
| nouveau_texture_functions_init(struct dd_function_table *functions) |
| { |
| functions->NewTextureObject = nouveau_texture_new; |
| functions->DeleteTexture = nouveau_texture_free; |
| functions->NewTextureImage = nouveau_teximage_new; |
| functions->FreeTextureImageBuffer = nouveau_teximage_free; |
| functions->AllocTextureImageBuffer = nouveau_teximage_alloc; |
| functions->ChooseTextureFormat = nouveau_choose_tex_format; |
| 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->MapTextureImage = nouveau_map_texture_image; |
| functions->UnmapTextureImage = nouveau_unmap_texture_image; |
| } |