st_texture.c revision e9d156e9e4f92ae1ce70bd563c251b34d238c4bc
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_public.h"
31#include "st_texture.h"
32#include "st_cb_fbo.h"
33#include "main/enums.h"
34#include "main/teximage.h"
35#include "main/texstore.h"
36
37#undef Elements  /* fix re-defined macro warning */
38
39#include "pipe/p_state.h"
40#include "pipe/p_context.h"
41#include "pipe/p_defines.h"
42#include "pipe/p_inlines.h"
43#include "util/u_rect.h"
44
45
46#define DBG if(0) printf
47
48#if 0
49static GLenum
50target_to_target(GLenum target)
51{
52   switch (target) {
53   case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB:
54   case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB:
55   case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB:
56   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB:
57   case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB:
58   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB:
59      return GL_TEXTURE_CUBE_MAP_ARB;
60   default:
61      return target;
62   }
63}
64#endif
65
66
67/**
68 * Allocate a new pipe_texture object
69 * width0, height0, depth0 are the dimensions of the level 0 image
70 * (the highest resolution).  last_level indicates how many mipmap levels
71 * to allocate storage for.  For non-mipmapped textures, this will be zero.
72 */
73struct pipe_texture *
74st_texture_create(struct st_context *st,
75                  enum pipe_texture_target target,
76		  enum pipe_format format,
77		  GLuint last_level,
78		  GLuint width0,
79		  GLuint height0,
80		  GLuint depth0,
81		  GLuint compress_byte,
82                  GLuint usage )
83{
84   struct pipe_texture pt, *newtex;
85   struct pipe_screen *screen = st->pipe->screen;
86
87   assert(target <= PIPE_TEXTURE_CUBE);
88
89   DBG("%s target %s format %s last_level %d\n", __FUNCTION__,
90       _mesa_lookup_enum_by_nr(target),
91       _mesa_lookup_enum_by_nr(format), last_level);
92
93   assert(format);
94   assert(screen->is_format_supported(screen, format, target,
95                                      PIPE_TEXTURE_USAGE_SAMPLER, 0));
96
97   memset(&pt, 0, sizeof(pt));
98   pt.target = target;
99   pt.format = format;
100   pt.last_level = last_level;
101   pt.width[0] = width0;
102   pt.height[0] = height0;
103   pt.depth[0] = depth0;
104   pt.compressed = compress_byte ? 1 : 0;
105   pf_get_block(format, &pt.block);
106   pt.tex_usage = usage;
107
108   newtex = screen->texture_create(screen, &pt);
109
110   assert(!newtex || pipe_is_referenced(&newtex->reference));
111
112   return newtex;
113}
114
115
116/**
117 * Check if a texture image can be pulled into a unified mipmap texture.
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   /* Check if this image's format matches the established texture's format.
130    */
131   if (st_mesa_format_to_pipe_format(image->TexFormat->MesaFormat) != pt->format ||
132       image->IsCompressed != pt->compressed)
133      return GL_FALSE;
134
135   /* Test if this image's size matches what's expected in the
136    * established texture.
137    */
138   if (image->Width != pt->width[level] ||
139       image->Height != pt->height[level] ||
140       image->Depth != pt->depth[level])
141      return GL_FALSE;
142
143   return GL_TRUE;
144}
145
146
147#if 000
148/* Although we use the image_offset[] array to store relative offsets
149 * to cube faces, Mesa doesn't know anything about this and expects
150 * each cube face to be treated as a separate image.
151 *
152 * These functions present that view to mesa:
153 */
154const GLuint *
155st_texture_depth_offsets(struct pipe_texture *pt, GLuint level)
156{
157   static const GLuint zero = 0;
158
159   if (pt->target != PIPE_TEXTURE_3D || pt->level[level].nr_images == 1)
160      return &zero;
161   else
162      return pt->level[level].image_offset;
163}
164
165
166/**
167 * Return the offset to the given mipmap texture image within the
168 * texture memory buffer, in bytes.
169 */
170GLuint
171st_texture_image_offset(const struct pipe_texture * pt,
172                        GLuint face, GLuint level)
173{
174   if (pt->target == PIPE_TEXTURE_CUBE)
175      return (pt->level[level].level_offset +
176              pt->level[level].image_offset[face] * pt->cpp);
177   else
178      return pt->level[level].level_offset;
179}
180#endif
181
182
183/**
184 * Map a teximage in a mipmap texture.
185 * \param row_stride  returns row stride in bytes
186 * \param image_stride  returns image stride in bytes (for 3D textures).
187 * \return address of mapping
188 */
189GLubyte *
190st_texture_image_map(struct st_context *st, struct st_texture_image *stImage,
191		     GLuint zoffset, enum pipe_transfer_usage usage,
192                     GLuint x, GLuint y, GLuint w, GLuint h)
193{
194   struct pipe_screen *screen = st->pipe->screen;
195   struct pipe_texture *pt = stImage->pt;
196   DBG("%s \n", __FUNCTION__);
197
198   stImage->transfer = screen->get_tex_transfer(screen, pt, stImage->face,
199                                                stImage->level, zoffset,
200                                                usage, x, y, w, h);
201
202   if (stImage->transfer)
203      return screen->transfer_map(screen, stImage->transfer);
204   else
205      return NULL;
206}
207
208
209void
210st_texture_image_unmap(struct st_context *st,
211                       struct st_texture_image *stImage)
212{
213   struct pipe_screen *screen = st->pipe->screen;
214
215   DBG("%s\n", __FUNCTION__);
216
217   screen->transfer_unmap(screen, stImage->transfer);
218
219   screen->tex_transfer_destroy(stImage->transfer);
220}
221
222
223
224/**
225 * Upload data to a rectangular sub-region.  Lots of choices how to do this:
226 *
227 * - memcpy by span to current destination
228 * - upload data as new buffer and blit
229 *
230 * Currently always memcpy.
231 */
232static void
233st_surface_data(struct pipe_context *pipe,
234		struct pipe_transfer *dst,
235		unsigned dstx, unsigned dsty,
236		const void *src, unsigned src_stride,
237		unsigned srcx, unsigned srcy, unsigned width, unsigned height)
238{
239   struct pipe_screen *screen = pipe->screen;
240   void *map = screen->transfer_map(screen, dst);
241
242   pipe_copy_rect(map,
243                  &dst->block,
244                  dst->stride,
245                  dstx, dsty,
246                  width, height,
247                  src, src_stride,
248                  srcx, srcy);
249
250   screen->transfer_unmap(screen, dst);
251}
252
253
254/* Upload data for a particular image.
255 */
256void
257st_texture_image_data(struct pipe_context *pipe,
258                      struct pipe_texture *dst,
259                      GLuint face,
260                      GLuint level,
261                      void *src,
262                      GLuint src_row_stride, GLuint src_image_stride)
263{
264   struct pipe_screen *screen = pipe->screen;
265   GLuint depth = dst->depth[level];
266   GLuint i;
267   const GLubyte *srcUB = src;
268   struct pipe_transfer *dst_transfer;
269
270   DBG("%s\n", __FUNCTION__);
271   for (i = 0; i < depth; i++) {
272      dst_transfer = screen->get_tex_transfer(screen, dst, face, level, i,
273                                              PIPE_TRANSFER_WRITE, 0, 0,
274                                              dst->width[level],
275                                              dst->height[level]);
276
277      st_surface_data(pipe, dst_transfer,
278		      0, 0,                             /* dstx, dsty */
279		      srcUB,
280		      src_row_stride,
281		      0, 0,                             /* source x, y */
282		      dst->width[level], dst->height[level]);       /* width, height */
283
284      screen->tex_transfer_destroy(dst_transfer);
285
286      srcUB += src_image_stride;
287   }
288}
289
290
291/* Copy mipmap image between textures
292 */
293void
294st_texture_image_copy(struct pipe_context *pipe,
295                      struct pipe_texture *dst, GLuint dstLevel,
296                      struct pipe_texture *src,
297                      GLuint face)
298{
299   struct pipe_screen *screen = pipe->screen;
300   GLuint width = dst->width[dstLevel];
301   GLuint height = dst->height[dstLevel];
302   GLuint depth = dst->depth[dstLevel];
303   struct pipe_surface *src_surface;
304   struct pipe_surface *dst_surface;
305   GLuint i;
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			 dst_surface,
344			 0, 0, /* destX, Y */
345			 src_surface,
346			 0, 0, /* srcX, Y */
347			 width, height);
348
349      pipe_surface_reference(&src_surface, NULL);
350      pipe_surface_reference(&dst_surface, NULL);
351   }
352}
353
354/** Bind a pipe surface for use as a texture image */
355int
356st_set_teximage(struct pipe_texture *pt, int target)
357{
358   GET_CURRENT_CONTEXT(ctx);
359   const GLuint unit = ctx->Texture.CurrentUnit;
360   struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
361   struct gl_texture_object *texObj;
362   struct gl_texture_image *texImage;
363   struct st_texture_image *stImage;
364   int internalFormat;
365
366   switch (pt->format) {
367   case PIPE_FORMAT_A8R8G8B8_UNORM:
368      internalFormat = GL_RGBA8;
369      break;
370   default:
371      return 0;
372   };
373
374   switch (target) {
375   case ST_TEXTURE_2D:
376      target = GL_TEXTURE_2D;
377      break;
378   case ST_TEXTURE_RECT:
379      target = GL_TEXTURE_RECTANGLE_ARB;
380      break;
381   default:
382      return 0;
383   }
384
385   texObj = _mesa_select_tex_object(ctx, texUnit, target);
386   texImage = _mesa_get_tex_image(ctx, texObj, target, 0);
387   stImage = st_texture_image(texImage);
388
389   _mesa_init_teximage_fields(ctx, GL_TEXTURE_2D, texImage, pt->width[0],
390                              pt->height[0], 1, 0, internalFormat);
391
392   texImage->TexFormat = st_ChooseTextureFormat(ctx, internalFormat, GL_RGBA,
393                                                GL_UNSIGNED_BYTE);
394   _mesa_set_fetch_functions(texImage, 2);
395
396   pipe_texture_reference(&stImage->pt, pt);
397
398   return 1;
399}
400
401/** Redirect rendering into stfb's surface to a texture image */
402int
403st_bind_teximage(struct st_framebuffer *stfb, uint surfIndex,
404                 int target, int format, int level)
405{
406   GET_CURRENT_CONTEXT(ctx);
407   struct st_context *st = ctx->st;
408   struct pipe_context *pipe = st->pipe;
409   struct pipe_screen *screen = pipe->screen;
410   const GLuint unit = ctx->Texture.CurrentUnit;
411   struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
412   struct gl_texture_object *texObj;
413   struct gl_texture_image *texImage;
414   struct st_texture_image *stImage;
415   struct st_renderbuffer *strb;
416   GLint face = 0, slice = 0;
417
418   assert(surfIndex <= ST_SURFACE_DEPTH);
419
420   strb = st_renderbuffer(stfb->Base.Attachment[surfIndex].Renderbuffer);
421
422   if (strb->texture_save || strb->surface_save) {
423      /* Error! */
424      return 0;
425   }
426
427   if (target == ST_TEXTURE_2D) {
428      texObj = texUnit->CurrentTex[TEXTURE_2D_INDEX];
429      texImage = _mesa_get_tex_image(ctx, texObj, GL_TEXTURE_2D, level);
430      stImage = st_texture_image(texImage);
431   }
432   else {
433      /* unsupported target */
434      return 0;
435   }
436
437   st_flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, NULL);
438
439   /* save the renderbuffer's surface/texture info */
440   pipe_texture_reference(&strb->texture_save, strb->texture);
441   pipe_surface_reference(&strb->surface_save, strb->surface);
442
443   /* plug in new surface/texture info */
444   pipe_texture_reference(&strb->texture, stImage->pt);
445   strb->surface = screen->get_tex_surface(screen, strb->texture,
446                                           face, level, slice,
447                                           (PIPE_BUFFER_USAGE_GPU_READ |
448                                            PIPE_BUFFER_USAGE_GPU_WRITE));
449
450   st->dirty.st |= ST_NEW_FRAMEBUFFER;
451
452   return 1;
453}
454
455
456/** Undo surface-to-texture binding */
457int
458st_release_teximage(struct st_framebuffer *stfb, uint surfIndex,
459                    int target, int format, int level)
460{
461   GET_CURRENT_CONTEXT(ctx);
462   struct st_context *st = ctx->st;
463   struct st_renderbuffer *strb;
464
465   assert(surfIndex <= ST_SURFACE_DEPTH);
466
467   strb = st_renderbuffer(stfb->Base.Attachment[surfIndex].Renderbuffer);
468
469   if (!strb->texture_save || !strb->surface_save) {
470      /* Error! */
471      return 0;
472   }
473
474   st_flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, NULL);
475
476   /* free tex surface, restore original */
477   pipe_surface_reference(&strb->surface, strb->surface_save);
478   pipe_texture_reference(&strb->texture, strb->texture_save);
479
480   pipe_surface_reference(&strb->surface_save, NULL);
481   pipe_texture_reference(&strb->texture_save, NULL);
482
483   st->dirty.st |= ST_NEW_FRAMEBUFFER;
484
485   return 1;
486}
487