st_texture.c revision f5bd93fae2e4f46665eb1f09ca64cb39ff2b8a79
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 "st_inlines.h"
34#include "main/enums.h"
35#include "main/texfetch.h"
36#include "main/teximage.h"
37#include "main/texobj.h"
38#include "main/texstore.h"
39
40#undef Elements  /* fix re-defined macro warning */
41
42#include "pipe/p_state.h"
43#include "pipe/p_context.h"
44#include "pipe/p_defines.h"
45#include "pipe/p_inlines.h"
46#include "util/u_format.h"
47#include "util/u_rect.h"
48#include "util/u_math.h"
49
50
51#define DBG if(0) printf
52
53#if 0
54static GLenum
55target_to_target(GLenum target)
56{
57   switch (target) {
58   case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB:
59   case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB:
60   case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB:
61   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB:
62   case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB:
63   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB:
64      return GL_TEXTURE_CUBE_MAP_ARB;
65   default:
66      return target;
67   }
68}
69#endif
70
71
72/**
73 * Allocate a new pipe_texture object
74 * width0, height0, depth0 are the dimensions of the level 0 image
75 * (the highest resolution).  last_level indicates how many mipmap levels
76 * to allocate storage for.  For non-mipmapped textures, this will be zero.
77 */
78struct pipe_texture *
79st_texture_create(struct st_context *st,
80                  enum pipe_texture_target target,
81		  enum pipe_format format,
82		  GLuint last_level,
83		  GLuint width0,
84		  GLuint height0,
85		  GLuint depth0,
86                  GLuint usage )
87{
88   struct pipe_texture pt, *newtex;
89   struct pipe_screen *screen = st->pipe->screen;
90
91   assert(target <= PIPE_TEXTURE_CUBE);
92
93   DBG("%s target %s format %s last_level %d\n", __FUNCTION__,
94       _mesa_lookup_enum_by_nr(target),
95       _mesa_lookup_enum_by_nr(format), last_level);
96
97   assert(format);
98   assert(screen->is_format_supported(screen, format, target,
99                                      PIPE_TEXTURE_USAGE_SAMPLER, 0));
100
101   memset(&pt, 0, sizeof(pt));
102   pt.target = target;
103   pt.format = format;
104   pt.last_level = last_level;
105   pt.width0 = width0;
106   pt.height0 = height0;
107   pt.depth0 = depth0;
108   util_format_get_block(format, &pt.block);
109   pt.tex_usage = usage;
110
111   newtex = screen->texture_create(screen, &pt);
112
113   assert(!newtex || pipe_is_referenced(&newtex->reference));
114
115   return newtex;
116}
117
118
119/**
120 * Check if a texture image can be pulled into a unified mipmap texture.
121 */
122GLboolean
123st_texture_match_image(const struct pipe_texture *pt,
124                       const struct gl_texture_image *image,
125                       GLuint face, GLuint level)
126{
127   /* Images with borders are never pulled into mipmap textures.
128    */
129   if (image->Border)
130      return GL_FALSE;
131
132   /* Check if this image's format matches the established texture's format.
133    */
134   if (st_mesa_format_to_pipe_format(image->TexFormat) != pt->format)
135      return GL_FALSE;
136
137   /* Test if this image's size matches what's expected in the
138    * established texture.
139    */
140   if (image->Width != u_minify(pt->width0, level) ||
141       image->Height != u_minify(pt->height0, level) ||
142       image->Depth != u_minify(pt->depth0, level))
143      return GL_FALSE;
144
145   return GL_TRUE;
146}
147
148
149#if 000
150/* Although we use the image_offset[] array to store relative offsets
151 * to cube faces, Mesa doesn't know anything about this and expects
152 * each cube face to be treated as a separate image.
153 *
154 * These functions present that view to mesa:
155 */
156const GLuint *
157st_texture_depth_offsets(struct pipe_texture *pt, GLuint level)
158{
159   static const GLuint zero = 0;
160
161   if (pt->target != PIPE_TEXTURE_3D || pt->level[level].nr_images == 1)
162      return &zero;
163   else
164      return pt->level[level].image_offset;
165}
166
167
168/**
169 * Return the offset to the given mipmap texture image within the
170 * texture memory buffer, in bytes.
171 */
172GLuint
173st_texture_image_offset(const struct pipe_texture * pt,
174                        GLuint face, GLuint level)
175{
176   if (pt->target == PIPE_TEXTURE_CUBE)
177      return (pt->level[level].level_offset +
178              pt->level[level].image_offset[face] * pt->cpp);
179   else
180      return pt->level[level].level_offset;
181}
182#endif
183
184
185/**
186 * Map a teximage in a mipmap texture.
187 * \param row_stride  returns row stride in bytes
188 * \param image_stride  returns image stride in bytes (for 3D textures).
189 * \return address of mapping
190 */
191GLubyte *
192st_texture_image_map(struct st_context *st, struct st_texture_image *stImage,
193		     GLuint zoffset, enum pipe_transfer_usage usage,
194                     GLuint x, GLuint y, GLuint w, GLuint h)
195{
196   struct pipe_context *pipe = st->pipe;
197   struct pipe_screen *screen = pipe->screen;
198   struct pipe_texture *pt = stImage->pt;
199
200   DBG("%s \n", __FUNCTION__);
201
202   stImage->transfer = st_no_flush_get_tex_transfer(st, pt, stImage->face,
203						    stImage->level, zoffset,
204						    usage, x, y, w, h);
205
206   if (stImage->transfer)
207      return screen->transfer_map(screen, stImage->transfer);
208   else
209      return NULL;
210}
211
212
213void
214st_texture_image_unmap(struct st_context *st,
215                       struct st_texture_image *stImage)
216{
217   struct pipe_screen *screen = st->pipe->screen;
218
219   DBG("%s\n", __FUNCTION__);
220
221   screen->transfer_unmap(screen, stImage->transfer);
222
223   screen->tex_transfer_destroy(stImage->transfer);
224}
225
226
227
228/**
229 * Upload data to a rectangular sub-region.  Lots of choices how to do this:
230 *
231 * - memcpy by span to current destination
232 * - upload data as new buffer and blit
233 *
234 * Currently always memcpy.
235 */
236static void
237st_surface_data(struct pipe_context *pipe,
238		struct pipe_transfer *dst,
239		unsigned dstx, unsigned dsty,
240		const void *src, unsigned src_stride,
241		unsigned srcx, unsigned srcy, unsigned width, unsigned height)
242{
243   struct pipe_screen *screen = pipe->screen;
244   void *map = screen->transfer_map(screen, dst);
245
246   util_copy_rect(map,
247                  &dst->block,
248                  dst->stride,
249                  dstx, dsty,
250                  width, height,
251                  src, src_stride,
252                  srcx, srcy);
253
254   screen->transfer_unmap(screen, dst);
255}
256
257
258/* Upload data for a particular image.
259 */
260void
261st_texture_image_data(struct st_context *st,
262                      struct pipe_texture *dst,
263                      GLuint face,
264                      GLuint level,
265                      void *src,
266                      GLuint src_row_stride, GLuint src_image_stride)
267{
268   struct pipe_context *pipe = st->pipe;
269   struct pipe_screen *screen = pipe->screen;
270   GLuint depth = u_minify(dst->depth0, level);
271   GLuint i;
272   const GLubyte *srcUB = src;
273   struct pipe_transfer *dst_transfer;
274
275   DBG("%s\n", __FUNCTION__);
276
277   for (i = 0; i < depth; i++) {
278      dst_transfer = st_no_flush_get_tex_transfer(st, dst, face, level, i,
279						  PIPE_TRANSFER_WRITE, 0, 0,
280						  u_minify(dst->width0, level),
281                                                  u_minify(dst->height0, level));
282
283      st_surface_data(pipe, dst_transfer,
284		      0, 0,                             /* dstx, dsty */
285		      srcUB,
286		      src_row_stride,
287		      0, 0,                             /* source x, y */
288		      u_minify(dst->width0, level),
289                      u_minify(dst->height0, level));      /* width, height */
290
291      screen->tex_transfer_destroy(dst_transfer);
292
293      srcUB += src_image_stride;
294   }
295}
296
297
298/* Copy mipmap image between textures
299 */
300void
301st_texture_image_copy(struct pipe_context *pipe,
302                      struct pipe_texture *dst, GLuint dstLevel,
303                      struct pipe_texture *src,
304                      GLuint face)
305{
306   struct pipe_screen *screen = pipe->screen;
307   GLuint width = u_minify(dst->width0, dstLevel);
308   GLuint height = u_minify(dst->height0, dstLevel);
309   GLuint depth = u_minify(dst->depth0, dstLevel);
310   struct pipe_surface *src_surface;
311   struct pipe_surface *dst_surface;
312   GLuint i;
313
314   for (i = 0; i < depth; i++) {
315      GLuint srcLevel;
316
317      /* find src texture level of needed size */
318      for (srcLevel = 0; srcLevel <= src->last_level; srcLevel++) {
319         if (u_minify(src->width0, srcLevel) == width &&
320             u_minify(src->height0, srcLevel) == height) {
321            break;
322         }
323      }
324      assert(u_minify(src->width0, srcLevel) == width);
325      assert(u_minify(src->height0, srcLevel) == height);
326
327#if 0
328      {
329         src_surface = screen->get_tex_surface(screen, src, face, srcLevel, i,
330                                               PIPE_BUFFER_USAGE_CPU_READ);
331         ubyte *map = screen->surface_map(screen, src_surface, PIPE_BUFFER_USAGE_CPU_READ);
332         map += src_surface->width * src_surface->height * 4 / 2;
333         printf("%s center pixel: %d %d %d %d (pt %p[%d] -> %p[%d])\n",
334                __FUNCTION__,
335                map[0], map[1], map[2], map[3],
336                src, srcLevel, dst, dstLevel);
337
338         screen->surface_unmap(screen, src_surface);
339         pipe_surface_reference(&src_surface, NULL);
340      }
341#endif
342
343      dst_surface = screen->get_tex_surface(screen, dst, face, dstLevel, i,
344                                            PIPE_BUFFER_USAGE_GPU_WRITE);
345
346      src_surface = screen->get_tex_surface(screen, src, face, srcLevel, i,
347                                            PIPE_BUFFER_USAGE_GPU_READ);
348
349      if (pipe->surface_copy) {
350         pipe->surface_copy(pipe,
351			    dst_surface,
352			    0, 0, /* destX, Y */
353			    src_surface,
354			    0, 0, /* srcX, Y */
355			    width, height);
356      } else {
357         util_surface_copy(pipe, FALSE,
358			   dst_surface,
359			   0, 0, /* destX, Y */
360			   src_surface,
361			   0, 0, /* srcX, Y */
362			   width, height);
363      }
364
365      pipe_surface_reference(&src_surface, NULL);
366      pipe_surface_reference(&dst_surface, NULL);
367   }
368}
369
370
371/**
372 * Bind a pipe surface to a texture object.  After the call,
373 * the texture object is marked dirty and will be (re-)validated.
374 *
375 * If this is the first surface bound, the texture object is said to
376 * switch from normal to surface based.  It will be cleared first in
377 * this case.
378 *
379 * \param ps      pipe surface to be unbound
380 * \param target  texture target
381 * \param level   image level
382 * \param format  internal format of the texture
383 */
384int
385st_bind_texture_surface(struct pipe_surface *ps, int target, int level,
386                        enum pipe_format format)
387{
388   GET_CURRENT_CONTEXT(ctx);
389   const GLuint unit = ctx->Texture.CurrentUnit;
390   struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
391   struct gl_texture_object *texObj;
392   struct gl_texture_image *texImage;
393   struct st_texture_object *stObj;
394   struct st_texture_image *stImage;
395   GLenum internalFormat;
396
397   switch (target) {
398   case ST_TEXTURE_2D:
399      target = GL_TEXTURE_2D;
400      break;
401   case ST_TEXTURE_RECT:
402      target = GL_TEXTURE_RECTANGLE_ARB;
403      break;
404   default:
405      return 0;
406   }
407
408   /* map pipe format to base format for now */
409   if (util_format_get_component_bits(format, UTIL_FORMAT_COLORSPACE_RGB, 3) > 0)
410      internalFormat = GL_RGBA;
411   else
412      internalFormat = GL_RGB;
413
414   texObj = _mesa_select_tex_object(ctx, texUnit, target);
415   _mesa_lock_texture(ctx, texObj);
416
417   stObj = st_texture_object(texObj);
418   /* switch to surface based */
419   if (!stObj->surface_based) {
420      _mesa_clear_texture_object(ctx, texObj);
421      stObj->surface_based = GL_TRUE;
422   }
423
424   texImage = _mesa_get_tex_image(ctx, texObj, target, level);
425   stImage = st_texture_image(texImage);
426
427   _mesa_init_teximage_fields(ctx, target, texImage,
428                              ps->width, ps->height, 1, 0, internalFormat);
429   texImage->TexFormat = st_ChooseTextureFormat(ctx, internalFormat,
430                                                GL_RGBA, GL_UNSIGNED_BYTE);
431   _mesa_set_fetch_functions(texImage, 2);
432   pipe_texture_reference(&stImage->pt, ps->texture);
433
434   _mesa_dirty_texobj(ctx, texObj, GL_TRUE);
435   _mesa_unlock_texture(ctx, texObj);
436
437   return 1;
438}
439
440
441/**
442 * Unbind a pipe surface from a texture object.  After the call,
443 * the texture object is marked dirty and will be (re-)validated.
444 *
445 * \param ps      pipe surface to be unbound
446 * \param target  texture target
447 * \param level   image level
448 */
449int
450st_unbind_texture_surface(struct pipe_surface *ps, int target, int level)
451{
452   GET_CURRENT_CONTEXT(ctx);
453   const GLuint unit = ctx->Texture.CurrentUnit;
454   struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
455   struct gl_texture_object *texObj;
456   struct gl_texture_image *texImage;
457   struct st_texture_object *stObj;
458   struct st_texture_image *stImage;
459
460   switch (target) {
461   case ST_TEXTURE_2D:
462      target = GL_TEXTURE_2D;
463      break;
464   case ST_TEXTURE_RECT:
465      target = GL_TEXTURE_RECTANGLE_ARB;
466      break;
467   default:
468      return 0;
469   }
470
471   texObj = _mesa_select_tex_object(ctx, texUnit, target);
472
473   _mesa_lock_texture(ctx, texObj);
474
475   texImage = _mesa_get_tex_image(ctx, texObj, target, level);
476   stObj = st_texture_object(texObj);
477   stImage = st_texture_image(texImage);
478
479   /* Make sure the pipe surface is still bound.  The texture object is still
480    * considered surface based even if this is the last bound surface. */
481   if (stImage->pt == ps->texture) {
482      pipe_texture_reference(&stImage->pt, NULL);
483      _mesa_clear_texture_image(ctx, texImage);
484
485      _mesa_dirty_texobj(ctx, texObj, GL_TRUE);
486   }
487
488   _mesa_unlock_texture(ctx, texObj);
489
490   return 1;
491}
492
493
494/** Redirect rendering into stfb's surface to a texture image */
495int
496st_bind_teximage(struct st_framebuffer *stfb, uint surfIndex,
497                 int target, int format, int level)
498{
499   GET_CURRENT_CONTEXT(ctx);
500   struct st_context *st = ctx->st;
501   struct pipe_context *pipe = st->pipe;
502   struct pipe_screen *screen = pipe->screen;
503   const GLuint unit = ctx->Texture.CurrentUnit;
504   struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
505   struct gl_texture_object *texObj;
506   struct gl_texture_image *texImage;
507   struct st_texture_image *stImage;
508   struct st_renderbuffer *strb;
509   GLint face = 0, slice = 0;
510
511   assert(surfIndex <= ST_SURFACE_DEPTH);
512
513   strb = st_renderbuffer(stfb->Base.Attachment[surfIndex].Renderbuffer);
514
515   if (strb->texture_save || strb->surface_save) {
516      /* Error! */
517      return 0;
518   }
519
520   if (target == ST_TEXTURE_2D) {
521      texObj = texUnit->CurrentTex[TEXTURE_2D_INDEX];
522      texImage = _mesa_get_tex_image(ctx, texObj, GL_TEXTURE_2D, level);
523      stImage = st_texture_image(texImage);
524   }
525   else {
526      /* unsupported target */
527      return 0;
528   }
529
530   st_flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, NULL);
531
532   /* save the renderbuffer's surface/texture info */
533   pipe_texture_reference(&strb->texture_save, strb->texture);
534   pipe_surface_reference(&strb->surface_save, strb->surface);
535
536   /* plug in new surface/texture info */
537   pipe_texture_reference(&strb->texture, stImage->pt);
538   strb->surface = screen->get_tex_surface(screen, strb->texture,
539                                           face, level, slice,
540                                           (PIPE_BUFFER_USAGE_GPU_READ |
541                                            PIPE_BUFFER_USAGE_GPU_WRITE));
542
543   st->dirty.st |= ST_NEW_FRAMEBUFFER;
544
545   return 1;
546}
547
548
549/** Undo surface-to-texture binding */
550int
551st_release_teximage(struct st_framebuffer *stfb, uint surfIndex,
552                    int target, int format, int level)
553{
554   GET_CURRENT_CONTEXT(ctx);
555   struct st_context *st = ctx->st;
556   struct st_renderbuffer *strb;
557
558   assert(surfIndex <= ST_SURFACE_DEPTH);
559
560   strb = st_renderbuffer(stfb->Base.Attachment[surfIndex].Renderbuffer);
561
562   if (!strb->texture_save || !strb->surface_save) {
563      /* Error! */
564      return 0;
565   }
566
567   st_flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, NULL);
568
569   /* free tex surface, restore original */
570   pipe_surface_reference(&strb->surface, strb->surface_save);
571   pipe_texture_reference(&strb->texture, strb->texture_save);
572
573   pipe_surface_reference(&strb->surface_save, NULL);
574   pipe_texture_reference(&strb->texture_save, NULL);
575
576   st->dirty.st |= ST_NEW_FRAMEBUFFER;
577
578   return 1;
579}
580
581void
582st_teximage_flush_before_map(struct st_context *st,
583			     struct pipe_texture *pt,
584			     unsigned int face,
585			     unsigned int level,
586			     enum pipe_transfer_usage usage)
587{
588   struct pipe_context *pipe = st->pipe;
589   unsigned referenced =
590      pipe->is_texture_referenced(pipe, pt, face, level);
591
592   if (referenced && ((referenced & PIPE_REFERENCED_FOR_WRITE) ||
593		      (usage & PIPE_TRANSFER_WRITE)))
594      st->pipe->flush(st->pipe, PIPE_FLUSH_RENDER_CACHE, NULL);
595}
596