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