st_texture.c revision 4ddd65967915ca4846f2831bc676c878a29dae4a
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#undef Elements  /* fix re-defined macro warning */
34
35#include "pipe/p_state.h"
36#include "pipe/p_context.h"
37#include "pipe/p_defines.h"
38#include "pipe/p_inlines.h"
39#include "pipe/p_util.h"
40#include "pipe/p_inlines.h"
41
42
43#define DBG if(0) printf
44
45#if 0
46static GLenum
47target_to_target(GLenum target)
48{
49   switch (target) {
50   case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB:
51   case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB:
52   case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB:
53   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB:
54   case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB:
55   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB:
56      return GL_TEXTURE_CUBE_MAP_ARB;
57   default:
58      return target;
59   }
60}
61#endif
62
63
64/**
65 * Allocate a new pipe_texture object
66 * width0, height0, depth0 are the dimensions of the level 0 image
67 * (the highest resolution).  last_level indicates how many mipmap levels
68 * to allocate storage for.  For non-mipmapped textures, this will be zero.
69 */
70struct pipe_texture *
71st_texture_create(struct st_context *st,
72                  enum pipe_texture_target target,
73		  enum pipe_format format,
74		  GLuint last_level,
75		  GLuint width0,
76		  GLuint height0,
77		  GLuint depth0,
78		  GLuint compress_byte,
79                  GLuint usage )
80{
81   struct pipe_texture pt, *newtex;
82   struct pipe_screen *screen = st->pipe->screen;
83
84   assert(target <= PIPE_TEXTURE_CUBE);
85
86   DBG("%s target %s format %s last_level %d\n", __FUNCTION__,
87       _mesa_lookup_enum_by_nr(target),
88       _mesa_lookup_enum_by_nr(format), last_level);
89
90   assert(format);
91   assert(screen->is_format_supported(screen, format, PIPE_TEXTURE));
92
93   memset(&pt, 0, sizeof(pt));
94   pt.target = target;
95   pt.format = format;
96   pt.last_level = last_level;
97   pt.width[0] = width0;
98   pt.height[0] = height0;
99   pt.depth[0] = depth0;
100   pt.compressed = compress_byte ? 1 : 0;
101   pf_get_block(format, &pt.block);
102   pt.tex_usage = usage;
103
104   newtex = screen->texture_create(screen, &pt);
105
106   assert(!newtex || newtex->refcount == 1);
107
108   return newtex;
109}
110
111
112/**
113 * Check if a texture image be pulled into a unified mipmap texture.
114 * This mirrors the completeness test in a lot of ways.
115 *
116 * Not sure whether I want to pass gl_texture_image here.
117 */
118GLboolean
119st_texture_match_image(const struct pipe_texture *pt,
120                       const struct gl_texture_image *image,
121                       GLuint face, GLuint level)
122{
123   /* Images with borders are never pulled into mipmap textures.
124    */
125   if (image->Border)
126      return GL_FALSE;
127
128   if (st_mesa_format_to_pipe_format(image->TexFormat->MesaFormat) != pt->format ||
129       image->IsCompressed != pt->compressed)
130      return GL_FALSE;
131
132   /* Test image dimensions against the base level image adjusted for
133    * minification.  This will also catch images not present in the
134    * texture, changed targets, etc.
135    */
136   if (image->Width != pt->width[level] ||
137       image->Height != pt->height[level] ||
138       image->Depth != pt->depth[level])
139      return GL_FALSE;
140
141   return GL_TRUE;
142}
143
144
145#if 000
146/* Although we use the image_offset[] array to store relative offsets
147 * to cube faces, Mesa doesn't know anything about this and expects
148 * each cube face to be treated as a separate image.
149 *
150 * These functions present that view to mesa:
151 */
152const GLuint *
153st_texture_depth_offsets(struct pipe_texture *pt, GLuint level)
154{
155   static const GLuint zero = 0;
156
157   if (pt->target != PIPE_TEXTURE_3D || pt->level[level].nr_images == 1)
158      return &zero;
159   else
160      return pt->level[level].image_offset;
161}
162
163
164/**
165 * Return the offset to the given mipmap texture image within the
166 * texture memory buffer, in bytes.
167 */
168GLuint
169st_texture_image_offset(const struct pipe_texture * pt,
170                        GLuint face, GLuint level)
171{
172   if (pt->target == PIPE_TEXTURE_CUBE)
173      return (pt->level[level].level_offset +
174              pt->level[level].image_offset[face] * pt->cpp);
175   else
176      return pt->level[level].level_offset;
177}
178#endif
179
180
181/**
182 * Map a teximage in a mipmap texture.
183 * \param row_stride  returns row stride in bytes
184 * \param image_stride  returns image stride in bytes (for 3D textures).
185 * \return address of mapping
186 */
187GLubyte *
188st_texture_image_map(struct st_context *st, struct st_texture_image *stImage,
189		     GLuint zoffset,
190                     GLuint flags )
191{
192   struct pipe_screen *screen = st->pipe->screen;
193   struct pipe_texture *pt = stImage->pt;
194   DBG("%s \n", __FUNCTION__);
195
196   stImage->surface = screen->get_tex_surface(screen, pt, stImage->face,
197                                              stImage->level, zoffset,
198                                              flags);
199
200   if (stImage->surface)
201      return screen->surface_map(screen, stImage->surface, flags);
202   else
203      return NULL;
204}
205
206
207void
208st_texture_image_unmap(struct st_context *st,
209                       struct st_texture_image *stImage)
210{
211   struct pipe_screen *screen = st->pipe->screen;
212
213   DBG("%s\n", __FUNCTION__);
214
215   screen->surface_unmap(screen, stImage->surface);
216
217   pipe_surface_reference(&stImage->surface, NULL);
218}
219
220
221
222/**
223 * Upload data to a rectangular sub-region.  Lots of choices how to do this:
224 *
225 * - memcpy by span to current destination
226 * - upload data as new buffer and blit
227 *
228 * Currently always memcpy.
229 */
230static void
231st_surface_data(struct pipe_context *pipe,
232		struct pipe_surface *dst,
233		unsigned dstx, unsigned dsty,
234		const void *src, unsigned src_stride,
235		unsigned srcx, unsigned srcy, unsigned width, unsigned height)
236{
237   struct pipe_screen *screen = pipe->screen;
238   void *map = screen->surface_map(screen, dst, PIPE_BUFFER_USAGE_CPU_WRITE);
239
240   pipe_copy_rect(map,
241                  &dst->block,
242                  dst->stride,
243                  dstx, dsty,
244                  width, height,
245                  src, src_stride,
246                  srcx, srcy);
247
248   screen->surface_unmap(screen, dst);
249}
250
251
252/* Upload data for a particular image.
253 */
254void
255st_texture_image_data(struct pipe_context *pipe,
256                      struct pipe_texture *dst,
257                      GLuint face,
258                      GLuint level,
259                      void *src,
260                      GLuint src_row_stride, GLuint src_image_stride)
261{
262   struct pipe_screen *screen = pipe->screen;
263   GLuint depth = dst->depth[level];
264   GLuint i;
265   const GLubyte *srcUB = src;
266   struct pipe_surface *dst_surface;
267
268   DBG("%s\n", __FUNCTION__);
269   for (i = 0; i < depth; i++) {
270      dst_surface = screen->get_tex_surface(screen, dst, face, level, i,
271                                            PIPE_BUFFER_USAGE_CPU_WRITE);
272
273      st_surface_data(pipe, dst_surface,
274		      0, 0,                             /* dstx, dsty */
275		      srcUB,
276		      src_row_stride,
277		      0, 0,                             /* source x, y */
278		      dst->width[level], dst->height[level]);       /* width, height */
279
280      screen->tex_surface_release(screen, &dst_surface);
281
282      srcUB += src_image_stride;
283   }
284}
285
286
287/* Copy mipmap image between textures
288 */
289void
290st_texture_image_copy(struct pipe_context *pipe,
291                      struct pipe_texture *dst, GLuint dstLevel,
292                      struct pipe_texture *src,
293                      GLuint face)
294{
295   struct pipe_screen *screen = pipe->screen;
296   GLuint width = dst->width[dstLevel];
297   GLuint height = dst->height[dstLevel];
298   GLuint depth = dst->depth[dstLevel];
299   struct pipe_surface *src_surface;
300   struct pipe_surface *dst_surface;
301   GLuint i;
302
303   /* XXX this is a hack */
304   const GLuint copyHeight = dst->compressed ? height / 4 : height;
305
306   for (i = 0; i < depth; i++) {
307      GLuint srcLevel;
308
309      /* find src texture level of needed size */
310      for (srcLevel = 0; srcLevel <= src->last_level; srcLevel++) {
311         if (src->width[srcLevel] == width &&
312             src->height[srcLevel] == height) {
313            break;
314         }
315      }
316      assert(src->width[srcLevel] == width);
317      assert(src->height[srcLevel] == height);
318
319#if 0
320      {
321         src_surface = screen->get_tex_surface(screen, src, face, srcLevel, i,
322                                               PIPE_BUFFER_USAGE_CPU_READ);
323         ubyte *map = screen->surface_map(screen, src_surface, PIPE_BUFFER_USAGE_CPU_READ);
324         map += src_surface->width * src_surface->height * 4 / 2;
325         printf("%s center pixel: %d %d %d %d (pt %p[%d] -> %p[%d])\n",
326                __FUNCTION__,
327                map[0], map[1], map[2], map[3],
328                src, srcLevel, dst, dstLevel);
329
330         screen->surface_unmap(screen, src_surface);
331         pipe_surface_reference(&src_surface, NULL);
332      }
333#endif
334
335      dst_surface = screen->get_tex_surface(screen, dst, face, dstLevel, i,
336                                            PIPE_BUFFER_USAGE_GPU_WRITE);
337
338      src_surface = screen->get_tex_surface(screen, src, face, srcLevel, i,
339                                            PIPE_BUFFER_USAGE_GPU_READ);
340
341      pipe->surface_copy(pipe,
342                         FALSE,
343			 dst_surface,
344			 0, 0, /* destX, Y */
345			 src_surface,
346			 0, 0, /* srcX, Y */
347			 width, copyHeight);
348
349      screen->tex_surface_release(screen, &src_surface);
350      screen->tex_surface_release(screen, &dst_surface);
351   }
352}
353