st_texture.c revision 848b8605
1/**************************************************************************
2 *
3 * Copyright 2007 VMware, Inc.
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 VMWARE 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 <stdio.h>
29
30#include "st_context.h"
31#include "st_format.h"
32#include "st_texture.h"
33#include "st_cb_fbo.h"
34#include "main/enums.h"
35
36#include "pipe/p_state.h"
37#include "pipe/p_context.h"
38#include "pipe/p_defines.h"
39#include "util/u_inlines.h"
40#include "util/u_format.h"
41#include "util/u_rect.h"
42#include "util/u_math.h"
43#include "util/u_memory.h"
44
45
46#define DBG if(0) printf
47
48
49/**
50 * Allocate a new pipe_resource object
51 * width0, height0, depth0 are the dimensions of the level 0 image
52 * (the highest resolution).  last_level indicates how many mipmap levels
53 * to allocate storage for.  For non-mipmapped textures, this will be zero.
54 */
55struct pipe_resource *
56st_texture_create(struct st_context *st,
57                  enum pipe_texture_target target,
58		  enum pipe_format format,
59		  GLuint last_level,
60		  GLuint width0,
61		  GLuint height0,
62		  GLuint depth0,
63                  GLuint layers,
64                  GLuint nr_samples,
65                  GLuint bind )
66{
67   struct pipe_resource pt, *newtex;
68   struct pipe_screen *screen = st->pipe->screen;
69
70   assert(target < PIPE_MAX_TEXTURE_TYPES);
71   assert(width0 > 0);
72   assert(height0 > 0);
73   assert(depth0 > 0);
74   if (target == PIPE_TEXTURE_CUBE)
75      assert(layers == 6);
76
77   DBG("%s target %d format %s last_level %d\n", __FUNCTION__,
78       (int) target, util_format_name(format), last_level);
79
80   assert(format);
81   assert(screen->is_format_supported(screen, format, target, 0,
82                                      PIPE_BIND_SAMPLER_VIEW));
83
84   memset(&pt, 0, sizeof(pt));
85   pt.target = target;
86   pt.format = format;
87   pt.last_level = last_level;
88   pt.width0 = width0;
89   pt.height0 = height0;
90   pt.depth0 = depth0;
91   pt.array_size = (target == PIPE_TEXTURE_CUBE ? 6 : layers);
92   pt.usage = PIPE_USAGE_DEFAULT;
93   pt.bind = bind;
94   pt.flags = 0;
95   pt.nr_samples = nr_samples;
96
97   newtex = screen->resource_create(screen, &pt);
98
99   assert(!newtex || pipe_is_referenced(&newtex->reference));
100
101   return newtex;
102}
103
104
105/**
106 * In OpenGL the number of 1D array texture layers is the "height" and
107 * the number of 2D array texture layers is the "depth".  In Gallium the
108 * number of layers in an array texture is a separate 'array_size' field.
109 * This function converts dimensions from the former to the later.
110 */
111void
112st_gl_texture_dims_to_pipe_dims(GLenum texture,
113                                GLuint widthIn,
114                                GLuint heightIn,
115                                GLuint depthIn,
116                                GLuint *widthOut,
117                                GLuint *heightOut,
118                                GLuint *depthOut,
119                                GLuint *layersOut)
120{
121   switch (texture) {
122   case GL_TEXTURE_1D:
123   case GL_PROXY_TEXTURE_1D:
124      assert(heightIn == 1);
125      assert(depthIn == 1);
126      *widthOut = widthIn;
127      *heightOut = 1;
128      *depthOut = 1;
129      *layersOut = 1;
130      break;
131   case GL_TEXTURE_1D_ARRAY:
132   case GL_PROXY_TEXTURE_1D_ARRAY:
133      assert(depthIn == 1);
134      *widthOut = widthIn;
135      *heightOut = 1;
136      *depthOut = 1;
137      *layersOut = heightIn;
138      break;
139   case GL_TEXTURE_2D:
140   case GL_PROXY_TEXTURE_2D:
141   case GL_TEXTURE_RECTANGLE:
142   case GL_PROXY_TEXTURE_RECTANGLE:
143   case GL_TEXTURE_EXTERNAL_OES:
144   case GL_PROXY_TEXTURE_2D_MULTISAMPLE:
145   case GL_TEXTURE_2D_MULTISAMPLE:
146      assert(depthIn == 1);
147      *widthOut = widthIn;
148      *heightOut = heightIn;
149      *depthOut = 1;
150      *layersOut = 1;
151      break;
152   case GL_TEXTURE_CUBE_MAP:
153   case GL_PROXY_TEXTURE_CUBE_MAP:
154   case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
155   case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
156   case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
157   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
158   case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
159   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
160      assert(depthIn == 1);
161      *widthOut = widthIn;
162      *heightOut = heightIn;
163      *depthOut = 1;
164      *layersOut = 6;
165      break;
166   case GL_TEXTURE_2D_ARRAY:
167   case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
168   case GL_PROXY_TEXTURE_2D_ARRAY:
169   case GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY:
170      *widthOut = widthIn;
171      *heightOut = heightIn;
172      *depthOut = 1;
173      *layersOut = depthIn;
174      break;
175   case GL_TEXTURE_CUBE_MAP_ARRAY:
176   case GL_PROXY_TEXTURE_CUBE_MAP_ARRAY:
177      *widthOut = widthIn;
178      *heightOut = heightIn;
179      *depthOut = 1;
180      *layersOut = depthIn;
181      break;
182   default:
183      assert(0 && "Unexpected texture in st_gl_texture_dims_to_pipe_dims()");
184      /* fall-through */
185   case GL_TEXTURE_3D:
186   case GL_PROXY_TEXTURE_3D:
187      *widthOut = widthIn;
188      *heightOut = heightIn;
189      *depthOut = depthIn;
190      *layersOut = 1;
191      break;
192   }
193}
194
195
196/**
197 * Check if a texture image can be pulled into a unified mipmap texture.
198 */
199GLboolean
200st_texture_match_image(struct st_context *st,
201                       const struct pipe_resource *pt,
202                       const struct gl_texture_image *image)
203{
204   GLuint ptWidth, ptHeight, ptDepth, ptLayers;
205
206   /* Images with borders are never pulled into mipmap textures.
207    */
208   if (image->Border)
209      return GL_FALSE;
210
211   /* Check if this image's format matches the established texture's format.
212    */
213   if (st_mesa_format_to_pipe_format(st, image->TexFormat) != pt->format)
214      return GL_FALSE;
215
216   st_gl_texture_dims_to_pipe_dims(image->TexObject->Target,
217                                   image->Width, image->Height, image->Depth,
218                                   &ptWidth, &ptHeight, &ptDepth, &ptLayers);
219
220   /* Test if this image's size matches what's expected in the
221    * established texture.
222    */
223   if (ptWidth != u_minify(pt->width0, image->Level) ||
224       ptHeight != u_minify(pt->height0, image->Level) ||
225       ptDepth != u_minify(pt->depth0, image->Level) ||
226       ptLayers != pt->array_size)
227      return GL_FALSE;
228
229   return GL_TRUE;
230}
231
232
233/**
234 * Map a texture image and return the address for a particular 2D face/slice/
235 * layer.  The stImage indicates the cube face and mipmap level.  The slice
236 * of the 3D texture is passed in 'zoffset'.
237 * \param usage  one of the PIPE_TRANSFER_x values
238 * \param x, y, w, h  the region of interest of the 2D image.
239 * \return address of mapping or NULL if any error
240 */
241GLubyte *
242st_texture_image_map(struct st_context *st, struct st_texture_image *stImage,
243                     enum pipe_transfer_usage usage,
244                     GLuint x, GLuint y, GLuint z,
245                     GLuint w, GLuint h, GLuint d,
246                     struct pipe_transfer **transfer)
247{
248   struct st_texture_object *stObj =
249      st_texture_object(stImage->base.TexObject);
250   GLuint level;
251   void *map;
252
253   DBG("%s \n", __FUNCTION__);
254
255   if (!stImage->pt)
256      return NULL;
257
258   if (stObj->pt != stImage->pt)
259      level = 0;
260   else
261      level = stImage->base.Level;
262
263   z += stImage->base.Face;
264
265   map = pipe_transfer_map_3d(st->pipe, stImage->pt, level, usage,
266                              x, y, z, w, h, d, transfer);
267   if (map) {
268      /* Enlarge the transfer array if it's not large enough. */
269      if (z >= stImage->num_transfers) {
270         unsigned new_size = z + 1;
271
272         stImage->transfer = realloc(stImage->transfer,
273                     new_size * sizeof(struct st_texture_image_transfer));
274         memset(&stImage->transfer[stImage->num_transfers], 0,
275                (new_size - stImage->num_transfers) *
276                sizeof(struct st_texture_image_transfer));
277         stImage->num_transfers = new_size;
278      }
279
280      assert(!stImage->transfer[z].transfer);
281      stImage->transfer[z].transfer = *transfer;
282   }
283   return map;
284}
285
286
287void
288st_texture_image_unmap(struct st_context *st,
289                       struct st_texture_image *stImage, unsigned slice)
290{
291   struct pipe_context *pipe = st->pipe;
292   struct pipe_transfer **transfer =
293      &stImage->transfer[slice + stImage->base.Face].transfer;
294
295   DBG("%s\n", __FUNCTION__);
296
297   pipe_transfer_unmap(pipe, *transfer);
298   *transfer = NULL;
299}
300
301
302/* Upload data for a particular image.
303 */
304void
305st_texture_image_data(struct st_context *st,
306                      struct pipe_resource *dst,
307                      GLuint face,
308                      GLuint level,
309                      void *src,
310                      GLuint src_row_stride, GLuint src_image_stride)
311{
312   struct pipe_context *pipe = st->pipe;
313   GLuint i;
314   const GLubyte *srcUB = src;
315   GLuint layers;
316
317   if (dst->target == PIPE_TEXTURE_1D_ARRAY ||
318       dst->target == PIPE_TEXTURE_2D_ARRAY ||
319       dst->target == PIPE_TEXTURE_CUBE_ARRAY)
320      layers = dst->array_size;
321   else
322      layers = u_minify(dst->depth0, level);
323
324   DBG("%s\n", __FUNCTION__);
325
326   for (i = 0; i < layers; i++) {
327      struct pipe_box box;
328      u_box_2d_zslice(0, 0, face + i,
329                      u_minify(dst->width0, level),
330                      u_minify(dst->height0, level),
331                      &box);
332
333      pipe->transfer_inline_write(pipe, dst, level, PIPE_TRANSFER_WRITE,
334                                  &box, srcUB, src_row_stride, 0);
335
336      srcUB += src_image_stride;
337   }
338}
339
340
341/**
342 * For debug only: get/print center pixel in the src resource.
343 */
344static void
345print_center_pixel(struct pipe_context *pipe, struct pipe_resource *src)
346{
347   struct pipe_transfer *xfer;
348   struct pipe_box region;
349   ubyte *map;
350
351   region.x = src->width0 / 2;
352   region.y = src->height0 / 2;
353   region.z = 0;
354   region.width = 1;
355   region.height = 1;
356   region.depth = 1;
357
358   map = pipe->transfer_map(pipe, src, 0, PIPE_TRANSFER_READ, &region, &xfer);
359
360   printf("center pixel: %d %d %d %d\n", map[0], map[1], map[2], map[3]);
361
362   pipe->transfer_unmap(pipe, xfer);
363}
364
365
366/**
367 * Copy the image at level=0 in 'src' to the 'dst' resource at 'dstLevel'.
368 * This is used to copy mipmap images from one texture buffer to another.
369 * This typically happens when our initial guess at the total texture size
370 * is incorrect (see the guess_and_alloc_texture() function).
371 */
372void
373st_texture_image_copy(struct pipe_context *pipe,
374                      struct pipe_resource *dst, GLuint dstLevel,
375                      struct pipe_resource *src, GLuint srcLevel,
376                      GLuint face)
377{
378   GLuint width = u_minify(dst->width0, dstLevel);
379   GLuint height = u_minify(dst->height0, dstLevel);
380   GLuint depth = u_minify(dst->depth0, dstLevel);
381   struct pipe_box src_box;
382   GLuint i;
383
384   if (u_minify(src->width0, srcLevel) != width ||
385       u_minify(src->height0, srcLevel) != height ||
386       u_minify(src->depth0, srcLevel) != depth) {
387      /* The source image size doesn't match the destination image size.
388       * This can happen in some degenerate situations such as rendering to a
389       * cube map face which was set up with mismatched texture sizes.
390       */
391      return;
392   }
393
394   src_box.x = 0;
395   src_box.y = 0;
396   src_box.width = width;
397   src_box.height = height;
398   src_box.depth = 1;
399
400   if (src->target == PIPE_TEXTURE_1D_ARRAY ||
401       src->target == PIPE_TEXTURE_2D_ARRAY ||
402       src->target == PIPE_TEXTURE_CUBE_ARRAY) {
403      face = 0;
404      depth = src->array_size;
405   }
406
407   /* Loop over 3D image slices */
408   /* could (and probably should) use "true" 3d box here -
409      but drivers can't quite handle it yet */
410   for (i = face; i < face + depth; i++) {
411      src_box.z = i;
412
413      if (0)  {
414         print_center_pixel(pipe, src);
415      }
416
417      pipe->resource_copy_region(pipe,
418                                 dst,
419                                 dstLevel,
420                                 0, 0, i,/* destX, Y, Z */
421                                 src,
422                                 srcLevel,
423                                 &src_box);
424   }
425}
426
427
428struct pipe_resource *
429st_create_color_map_texture(struct gl_context *ctx)
430{
431   struct st_context *st = st_context(ctx);
432   struct pipe_resource *pt;
433   enum pipe_format format;
434   const uint texSize = 256; /* simple, and usually perfect */
435
436   /* find an RGBA texture format */
437   format = st_choose_format(st, GL_RGBA, GL_NONE, GL_NONE,
438                             PIPE_TEXTURE_2D, 0, PIPE_BIND_SAMPLER_VIEW,
439                             FALSE);
440
441   /* create texture for color map/table */
442   pt = st_texture_create(st, PIPE_TEXTURE_2D, format, 0,
443                          texSize, texSize, 1, 1, 0, PIPE_BIND_SAMPLER_VIEW);
444   return pt;
445}
446
447/**
448 * Try to find a matching sampler view for the given context.
449 * If none is found an empty slot is initialized with a
450 * template and returned instead.
451 */
452struct pipe_sampler_view **
453st_texture_get_sampler_view(struct st_context *st,
454                            struct st_texture_object *stObj)
455{
456   struct pipe_sampler_view *used = NULL, **free = NULL;
457   GLuint i;
458
459   for (i = 0; i < stObj->num_sampler_views; ++i) {
460      struct pipe_sampler_view **sv = &stObj->sampler_views[i];
461      /* Is the array entry used ? */
462      if (*sv) {
463         /* Yes, check if it's the right one */
464         if ((*sv)->context == st->pipe)
465            return sv;
466
467         /* Wasn't the right one, but remember it as template */
468         used = *sv;
469      } else {
470         /* Found a free slot, remember that */
471         free = sv;
472      }
473   }
474
475   /* Couldn't find a slot for our context, create a new one */
476
477   if (!free) {
478      /* Haven't even found a free one, resize the array */
479      GLuint old_size = stObj->num_sampler_views * sizeof(void *);
480      GLuint new_size = old_size + sizeof(void *);
481      stObj->sampler_views = REALLOC(stObj->sampler_views, old_size, new_size);
482      free = &stObj->sampler_views[stObj->num_sampler_views++];
483      *free = NULL;
484   }
485
486   /* Add just any sampler view to be used as a template */
487   if (used)
488      pipe_sampler_view_reference(free, used);
489
490   return free;
491}
492
493void
494st_texture_release_sampler_view(struct st_context *st,
495                                struct st_texture_object *stObj)
496{
497   GLuint i;
498
499   for (i = 0; i < stObj->num_sampler_views; ++i) {
500      struct pipe_sampler_view **sv = &stObj->sampler_views[i];
501
502      if (*sv && (*sv)->context == st->pipe) {
503         pipe_sampler_view_reference(sv, NULL);
504         break;
505      }
506   }
507}
508
509void
510st_texture_release_all_sampler_views(struct st_context *st,
511                                     struct st_texture_object *stObj)
512{
513   GLuint i;
514
515   /* XXX This should use sampler_views[i]->pipe, not st->pipe */
516   for (i = 0; i < stObj->num_sampler_views; ++i)
517      pipe_sampler_view_release(st->pipe, &stObj->sampler_views[i]);
518}
519
520
521void
522st_texture_free_sampler_views(struct st_texture_object *stObj)
523{
524   /* NOTE:
525    * We use FREE() here to match REALLOC() above.  Both come from
526    * u_memory.h, not imports.h.  If we mis-match MALLOC/FREE from
527    * those two headers we can trash the heap.
528    */
529   FREE(stObj->sampler_views);
530}
531