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