s_texture.c revision af69d88d
1/*
2 * Mesa 3-D graphics library
3 *
4 * Copyright (C) 2011 VMware, Inc.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 * OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25/**
26 * Functions for mapping/unmapping texture images.
27 */
28
29
30#include "main/context.h"
31#include "main/fbobject.h"
32#include "main/teximage.h"
33#include "main/texobj.h"
34#include "swrast/swrast.h"
35#include "swrast/s_context.h"
36
37
38/**
39 * Allocate a new swrast_texture_image (a subclass of gl_texture_image).
40 * Called via ctx->Driver.NewTextureImage().
41 */
42struct gl_texture_image *
43_swrast_new_texture_image( struct gl_context *ctx )
44{
45   (void) ctx;
46   return (struct gl_texture_image *) CALLOC_STRUCT(swrast_texture_image);
47}
48
49
50/**
51 * Free a swrast_texture_image (a subclass of gl_texture_image).
52 * Called via ctx->Driver.DeleteTextureImage().
53 */
54void
55_swrast_delete_texture_image(struct gl_context *ctx,
56                             struct gl_texture_image *texImage)
57{
58   /* Nothing special for the subclass yet */
59   _mesa_delete_texture_image(ctx, texImage);
60}
61
62static unsigned int
63texture_slices(struct gl_texture_image *texImage)
64{
65   if (texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY)
66      return texImage->Height;
67   else
68      return texImage->Depth;
69}
70
71unsigned int
72_swrast_teximage_slice_height(struct gl_texture_image *texImage)
73{
74   /* For 1D array textures, the slices are all 1 pixel high, and Height is
75    * the number of slices.
76    */
77   if (texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY)
78      return 1;
79   else
80      return texImage->Height;
81}
82
83/**
84 * Called via ctx->Driver.AllocTextureImageBuffer()
85 */
86GLboolean
87_swrast_alloc_texture_image_buffer(struct gl_context *ctx,
88                                   struct gl_texture_image *texImage)
89{
90   struct swrast_texture_image *swImg = swrast_texture_image(texImage);
91   GLuint bytesPerSlice;
92   GLuint slices = texture_slices(texImage);
93   GLuint i;
94
95   if (!_swrast_init_texture_image(texImage))
96      return GL_FALSE;
97
98   bytesPerSlice = _mesa_format_image_size(texImage->TexFormat, texImage->Width,
99                                           _swrast_teximage_slice_height(texImage), 1);
100
101   assert(!swImg->Buffer);
102   swImg->Buffer = _mesa_align_malloc(bytesPerSlice * slices, 512);
103   if (!swImg->Buffer)
104      return GL_FALSE;
105
106   /* RowStride and ImageSlices[] describe how to address texels in 'Data' */
107   swImg->RowStride = _mesa_format_row_stride(texImage->TexFormat,
108                                              texImage->Width);
109
110   for (i = 0; i < slices; i++) {
111      swImg->ImageSlices[i] = swImg->Buffer + bytesPerSlice * i;
112   }
113
114   return GL_TRUE;
115}
116
117
118/**
119 * Code that overrides ctx->Driver.AllocTextureImageBuffer may use this to
120 * initialize the fields of swrast_texture_image without allocating the image
121 * buffer or initializing RowStride or the contents of ImageSlices.
122 *
123 * Returns GL_TRUE on success, GL_FALSE on memory allocation failure.
124 */
125GLboolean
126_swrast_init_texture_image(struct gl_texture_image *texImage)
127{
128   struct swrast_texture_image *swImg = swrast_texture_image(texImage);
129
130   if ((texImage->Width == 1 || _mesa_is_pow_two(texImage->Width2)) &&
131       (texImage->Height == 1 || _mesa_is_pow_two(texImage->Height2)) &&
132       (texImage->Depth == 1 || _mesa_is_pow_two(texImage->Depth2)))
133      swImg->_IsPowerOfTwo = GL_TRUE;
134   else
135      swImg->_IsPowerOfTwo = GL_FALSE;
136
137   /* Compute Width/Height/DepthScale for mipmap lod computation */
138   if (texImage->TexObject->Target == GL_TEXTURE_RECTANGLE_NV) {
139      /* scale = 1.0 since texture coords directly map to texels */
140      swImg->WidthScale = 1.0;
141      swImg->HeightScale = 1.0;
142      swImg->DepthScale = 1.0;
143   }
144   else {
145      swImg->WidthScale = (GLfloat) texImage->Width;
146      swImg->HeightScale = (GLfloat) texImage->Height;
147      swImg->DepthScale = (GLfloat) texImage->Depth;
148   }
149
150   assert(!swImg->ImageSlices);
151   swImg->ImageSlices = calloc(texture_slices(texImage), sizeof(void *));
152   if (!swImg->ImageSlices)
153      return GL_FALSE;
154
155   return GL_TRUE;
156}
157
158
159/**
160 * Called via ctx->Driver.FreeTextureImageBuffer()
161 */
162void
163_swrast_free_texture_image_buffer(struct gl_context *ctx,
164                                  struct gl_texture_image *texImage)
165{
166   struct swrast_texture_image *swImage = swrast_texture_image(texImage);
167
168   _mesa_align_free(swImage->Buffer);
169   swImage->Buffer = NULL;
170
171   free(swImage->ImageSlices);
172   swImage->ImageSlices = NULL;
173}
174
175
176/**
177 * Error checking for debugging only.
178 */
179static void
180check_map_teximage(const struct gl_texture_image *texImage,
181                   GLuint slice, GLuint x, GLuint y, GLuint w, GLuint h)
182{
183
184   if (texImage->TexObject->Target == GL_TEXTURE_1D)
185      assert(y == 0 && h == 1);
186
187   assert(x < texImage->Width || texImage->Width == 0);
188   assert(y < texImage->Height || texImage->Height == 0);
189   assert(x + w <= texImage->Width);
190   assert(y + h <= texImage->Height);
191}
192
193/**
194 * Map a 2D slice of a texture image into user space.
195 * (x,y,w,h) defines a region of interest (ROI).  Reading/writing texels
196 * outside of the ROI is undefined.
197 *
198 * \param texImage  the texture image
199 * \param slice  the 3D image slice or array texture slice
200 * \param x, y, w, h  region of interest
201 * \param mode  bitmask of GL_MAP_READ_BIT, GL_MAP_WRITE_BIT
202 * \param mapOut  returns start of mapping of region of interest
203 * \param rowStrideOut  returns row stride (in bytes)
204 */
205void
206_swrast_map_teximage(struct gl_context *ctx,
207                     struct gl_texture_image *texImage,
208                     GLuint slice,
209                     GLuint x, GLuint y, GLuint w, GLuint h,
210                     GLbitfield mode,
211                     GLubyte **mapOut,
212                     GLint *rowStrideOut)
213{
214   struct swrast_texture_image *swImage = swrast_texture_image(texImage);
215   GLubyte *map;
216   GLint stride, texelSize;
217   GLuint bw, bh;
218
219   check_map_teximage(texImage, slice, x, y, w, h);
220
221   if (!swImage->Buffer) {
222      /* Either glTexImage was called with a NULL <pixels> argument or
223       * we ran out of memory when allocating texture memory,
224       */
225      *mapOut = NULL;
226      *rowStrideOut = 0;
227      return;
228   }
229
230   texelSize = _mesa_get_format_bytes(texImage->TexFormat);
231   stride = _mesa_format_row_stride(texImage->TexFormat, texImage->Width);
232   _mesa_get_format_block_size(texImage->TexFormat, &bw, &bh);
233
234   assert(x % bw == 0);
235   assert(y % bh == 0);
236
237   /* This function can only be used with a swrast-allocated buffer, in which
238    * case ImageSlices is populated with pointers into Buffer.
239    */
240   assert(swImage->Buffer);
241   assert(swImage->Buffer == swImage->ImageSlices[0]);
242
243   assert(slice < texture_slices(texImage));
244   map = swImage->ImageSlices[slice];
245
246   /* apply x/y offset to map address */
247   map += stride * (y / bh) + texelSize * (x / bw);
248
249   *mapOut = map;
250   *rowStrideOut = stride;
251}
252
253void
254_swrast_unmap_teximage(struct gl_context *ctx,
255                       struct gl_texture_image *texImage,
256                       GLuint slice)
257{
258   /* nop */
259}
260
261
262void
263_swrast_map_texture(struct gl_context *ctx, struct gl_texture_object *texObj)
264{
265   const GLuint faces = _mesa_num_tex_faces(texObj->Target);
266   GLuint face, level;
267
268   for (face = 0; face < faces; face++) {
269      for (level = texObj->BaseLevel; level < MAX_TEXTURE_LEVELS; level++) {
270         struct gl_texture_image *texImage = texObj->Image[face][level];
271         struct swrast_texture_image *swImage = swrast_texture_image(texImage);
272         unsigned int i, slices;
273
274         if (!texImage)
275            continue;
276
277         /* In the case of a swrast-allocated texture buffer, the ImageSlices
278          * and RowStride are always available.
279          */
280         if (swImage->Buffer) {
281            assert(swImage->ImageSlices[0] == swImage->Buffer);
282            continue;
283         }
284
285         if (!swImage->ImageSlices) {
286            swImage->ImageSlices =
287               calloc(texture_slices(texImage), sizeof(void *));
288            if (!swImage->ImageSlices)
289               continue;
290         }
291
292         slices = texture_slices(texImage);
293
294         for (i = 0; i < slices; i++) {
295            GLubyte *map;
296            GLint rowStride;
297
298            if (swImage->ImageSlices[i])
299               continue;
300
301            ctx->Driver.MapTextureImage(ctx, texImage, i,
302                                        0, 0,
303                                        texImage->Width, texImage->Height,
304                                        GL_MAP_READ_BIT | GL_MAP_WRITE_BIT,
305                                        &map, &rowStride);
306
307            swImage->ImageSlices[i] = map;
308            /* A swrast-using driver has to return the same rowstride for
309             * every slice of the same texture, since we don't track them
310             * separately.
311             */
312            if (i == 0)
313               swImage->RowStride = rowStride;
314            else
315               assert(swImage->RowStride == rowStride);
316         }
317      }
318   }
319}
320
321
322void
323_swrast_unmap_texture(struct gl_context *ctx, struct gl_texture_object *texObj)
324{
325   const GLuint faces = _mesa_num_tex_faces(texObj->Target);
326   GLuint face, level;
327
328   for (face = 0; face < faces; face++) {
329      for (level = texObj->BaseLevel; level < MAX_TEXTURE_LEVELS; level++) {
330         struct gl_texture_image *texImage = texObj->Image[face][level];
331         struct swrast_texture_image *swImage = swrast_texture_image(texImage);
332         unsigned int i, slices;
333
334         if (!texImage)
335            continue;
336
337         if (swImage->Buffer)
338            return;
339
340         if (!swImage->ImageSlices)
341            continue;
342
343         slices = texture_slices(texImage);
344
345         for (i = 0; i < slices; i++) {
346            if (swImage->ImageSlices[i]) {
347               ctx->Driver.UnmapTextureImage(ctx, texImage, i);
348               swImage->ImageSlices[i] = NULL;
349            }
350         }
351      }
352   }
353}
354
355
356/**
357 * Map all textures for reading prior to software rendering.
358 */
359void
360_swrast_map_textures(struct gl_context *ctx)
361{
362   int unit;
363
364   for (unit = 0; unit <= ctx->Texture._MaxEnabledTexImageUnit; unit++) {
365      struct gl_texture_object *texObj = ctx->Texture.Unit[unit]._Current;
366
367      if (texObj)
368         _swrast_map_texture(ctx, texObj);
369   }
370}
371
372
373/**
374 * Unmap all textures for reading prior to software rendering.
375 */
376void
377_swrast_unmap_textures(struct gl_context *ctx)
378{
379   int unit;
380   for (unit = 0; unit <= ctx->Texture._MaxEnabledTexImageUnit; unit++) {
381      struct gl_texture_object *texObj = ctx->Texture.Unit[unit]._Current;
382
383      if (texObj)
384         _swrast_unmap_texture(ctx, texObj);
385   }
386}
387