st_texture.c revision 01e53be2b80d5bcb48102f7f1be507b6a5a5832a
1/************************************************************************** 2 * 3 * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. 4 * All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the 8 * "Software"), to deal in the Software without restriction, including 9 * without limitation the rights to use, copy, modify, merge, publish, 10 * distribute, sub license, and/or sell copies of the Software, and to 11 * permit persons to whom the Software is furnished to do so, subject to 12 * the following conditions: 13 * 14 * The above copyright notice and this permission notice (including the 15 * next paragraph) shall be included in all copies or substantial portions 16 * of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR 22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 * 26 **************************************************************************/ 27 28#include "st_context.h" 29#include "st_format.h" 30#include "st_texture.h" 31#include "enums.h" 32 33#include "pipe/p_state.h" 34#include "pipe/p_context.h" 35#include "pipe/p_defines.h" 36#include "pipe/p_inlines.h" 37#include "pipe/p_util.h" 38#include "pipe/p_inlines.h" 39#include "pipe/p_winsys.h" 40 41 42#define DBG if(0) printf 43 44#if 0 45static GLenum 46target_to_target(GLenum target) 47{ 48 switch (target) { 49 case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB: 50 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB: 51 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB: 52 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB: 53 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB: 54 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB: 55 return GL_TEXTURE_CUBE_MAP_ARB; 56 default: 57 return target; 58 } 59} 60#endif 61 62 63/** 64 * Allocate a new pipe_texture object 65 * width0, height0, depth0 are the dimensions of the level 0 image 66 * (the highest resolution). last_level indicates how many mipmap levels 67 * to allocate storage for. For non-mipmapped textures, this will be zero. 68 */ 69struct pipe_texture * 70st_texture_create(struct st_context *st, 71 enum pipe_texture_target target, 72 enum pipe_format format, 73 GLuint last_level, 74 GLuint width0, 75 GLuint height0, 76 GLuint depth0, 77 GLuint compress_byte) 78{ 79 struct pipe_texture pt, *newtex; 80 struct pipe_screen *screen = st->pipe->screen; 81 82 assert(target <= PIPE_TEXTURE_CUBE); 83 84 DBG("%s target %s format %s last_level %d\n", __FUNCTION__, 85 _mesa_lookup_enum_by_nr(target), 86 _mesa_lookup_enum_by_nr(format), last_level); 87 88 assert(format); 89 assert(screen->is_format_supported(screen, format, PIPE_TEXTURE)); 90 91 memset(&pt, 0, sizeof(pt)); 92 pt.target = target; 93 pt.format = format; 94 pt.last_level = last_level; 95 pt.width[0] = width0; 96 pt.height[0] = height0; 97 pt.depth[0] = depth0; 98 pt.compressed = compress_byte ? 1 : 0; 99 pt.cpp = pt.compressed ? compress_byte : st_sizeof_format(format); 100 101 newtex = screen->texture_create(screen, &pt); 102 103 assert(!newtex || newtex->refcount == 1); 104 105 return newtex; 106} 107 108 109/** 110 * Check if a texture image be pulled into a unified mipmap texture. 111 * This mirrors the completeness test in a lot of ways. 112 * 113 * Not sure whether I want to pass gl_texture_image here. 114 */ 115GLboolean 116st_texture_match_image(const struct pipe_texture *pt, 117 const struct gl_texture_image *image, 118 GLuint face, GLuint level) 119{ 120 /* Images with borders are never pulled into mipmap textures. 121 */ 122 if (image->Border) 123 return GL_FALSE; 124 125 if (st_mesa_format_to_pipe_format(image->TexFormat->MesaFormat) != pt->format || 126 image->IsCompressed != pt->compressed) 127 return GL_FALSE; 128 129 /* Test image dimensions against the base level image adjusted for 130 * minification. This will also catch images not present in the 131 * texture, changed targets, etc. 132 */ 133 if (image->Width != pt->width[level] || 134 image->Height != pt->height[level] || 135 image->Depth != pt->depth[level]) 136 return GL_FALSE; 137 138 return GL_TRUE; 139} 140 141 142#if 000 143/* Although we use the image_offset[] array to store relative offsets 144 * to cube faces, Mesa doesn't know anything about this and expects 145 * each cube face to be treated as a separate image. 146 * 147 * These functions present that view to mesa: 148 */ 149const GLuint * 150st_texture_depth_offsets(struct pipe_texture *pt, GLuint level) 151{ 152 static const GLuint zero = 0; 153 154 if (pt->target != PIPE_TEXTURE_3D || pt->level[level].nr_images == 1) 155 return &zero; 156 else 157 return pt->level[level].image_offset; 158} 159 160 161/** 162 * Return the offset to the given mipmap texture image within the 163 * texture memory buffer, in bytes. 164 */ 165GLuint 166st_texture_image_offset(const struct pipe_texture * pt, 167 GLuint face, GLuint level) 168{ 169 if (pt->target == PIPE_TEXTURE_CUBE) 170 return (pt->level[level].level_offset + 171 pt->level[level].image_offset[face] * pt->cpp); 172 else 173 return pt->level[level].level_offset; 174} 175#endif 176 177 178/** 179 * Map a teximage in a mipmap texture. 180 * \param row_stride returns row stride in bytes 181 * \param image_stride returns image stride in bytes (for 3D textures). 182 * \return address of mapping 183 */ 184GLubyte * 185st_texture_image_map(struct st_context *st, struct st_texture_image *stImage, 186 GLuint zoffset) 187{ 188 struct pipe_screen *screen = st->pipe->screen; 189 struct pipe_texture *pt = stImage->pt; 190 DBG("%s \n", __FUNCTION__); 191 192 stImage->surface = screen->get_tex_surface(screen, pt, stImage->face, 193 stImage->level, zoffset); 194 195 return pipe_surface_map(stImage->surface); 196} 197 198 199void 200st_texture_image_unmap(struct st_texture_image *stImage) 201{ 202 DBG("%s\n", __FUNCTION__); 203 204 pipe_surface_unmap(stImage->surface); 205 206 pipe_surface_reference(&stImage->surface, NULL); 207} 208 209 210 211/** 212 * Upload data to a rectangular sub-region. Lots of choices how to do this: 213 * 214 * - memcpy by span to current destination 215 * - upload data as new buffer and blit 216 * 217 * Currently always memcpy. 218 */ 219static void 220st_surface_data(struct pipe_context *pipe, 221 struct pipe_surface *dst, 222 unsigned dstx, unsigned dsty, 223 const void *src, unsigned src_pitch, 224 unsigned srcx, unsigned srcy, unsigned width, unsigned height) 225{ 226 pipe_copy_rect(pipe_surface_map(dst), 227 dst->cpp, 228 dst->pitch, 229 dstx, dsty, width, height, src, src_pitch, srcx, srcy); 230 231 pipe_surface_unmap(dst); 232} 233 234 235/* Upload data for a particular image. 236 */ 237void 238st_texture_image_data(struct pipe_context *pipe, 239 struct pipe_texture *dst, 240 GLuint face, 241 GLuint level, 242 void *src, 243 GLuint src_row_pitch, GLuint src_image_pitch) 244{ 245 struct pipe_screen *screen = pipe->screen; 246 GLuint depth = dst->depth[level]; 247 GLuint i; 248 GLuint height = 0; 249 const GLubyte *srcUB = src; 250 struct pipe_surface *dst_surface; 251 252 DBG("%s\n", __FUNCTION__); 253 for (i = 0; i < depth; i++) { 254 height = dst->height[level]; 255 if(dst->compressed) 256 height /= 4; 257 258 dst_surface = screen->get_tex_surface(screen, dst, face, level, i); 259 260 st_surface_data(pipe, dst_surface, 261 0, 0, /* dstx, dsty */ 262 srcUB, 263 src_row_pitch, 264 0, 0, /* source x, y */ 265 dst->width[level], height); /* width, height */ 266 267 pipe_surface_reference(&dst_surface, NULL); 268 269 srcUB += src_image_pitch * dst->cpp; 270 } 271} 272 273 274/* Copy mipmap image between textures 275 */ 276void 277st_texture_image_copy(struct pipe_context *pipe, 278 struct pipe_texture *dst, GLuint dstLevel, 279 struct pipe_texture *src, 280 GLuint face) 281{ 282 struct pipe_screen *screen = pipe->screen; 283 GLuint width = dst->width[dstLevel]; 284 GLuint height = dst->height[dstLevel]; 285 GLuint depth = dst->depth[dstLevel]; 286 struct pipe_surface *src_surface; 287 struct pipe_surface *dst_surface; 288 GLuint i; 289 290 /* XXX this is a hack */ 291 if (dst->compressed) 292 height /= 4; 293 294 for (i = 0; i < depth; i++) { 295 GLuint srcLevel; 296 297 /* find src texture level of needed size */ 298 for (srcLevel = 0; srcLevel <= src->last_level; srcLevel++) { 299 if (src->width[srcLevel] == width && 300 src->height[srcLevel] == height) { 301 break; 302 } 303 } 304 assert(src->width[srcLevel] == width); 305 assert(src->height[srcLevel] == height); 306 307 dst_surface = screen->get_tex_surface(screen, dst, face, dstLevel, i); 308 src_surface = screen->get_tex_surface(screen, src, face, srcLevel, i); 309 310 pipe->surface_copy(pipe, 311 FALSE, 312 dst_surface, 313 0, 0, /* destX, Y */ 314 src_surface, 315 0, 0, /* srcX, Y */ 316 width, height); 317 318 pipe_surface_reference(&dst_surface, NULL); 319 pipe_surface_reference(&src_surface, NULL); 320 } 321} 322