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 BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
20  * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22  */
23 
24 /**
25  * Functions for mapping/unmapping texture images.
26  */
27 
28 
29 #include "main/context.h"
30 #include "main/fbobject.h"
31 #include "main/teximage.h"
32 #include "main/texobj.h"
33 #include "swrast/swrast.h"
34 #include "swrast/s_context.h"
35 
36 
37 /**
38  * Allocate a new swrast_texture_image (a subclass of gl_texture_image).
39  * Called via ctx->Driver.NewTextureImage().
40  */
41 struct gl_texture_image *
_swrast_new_texture_image(struct gl_context * ctx)42 _swrast_new_texture_image( struct gl_context *ctx )
43 {
44    (void) ctx;
45    return (struct gl_texture_image *) CALLOC_STRUCT(swrast_texture_image);
46 }
47 
48 
49 /**
50  * Free a swrast_texture_image (a subclass of gl_texture_image).
51  * Called via ctx->Driver.DeleteTextureImage().
52  */
53 void
_swrast_delete_texture_image(struct gl_context * ctx,struct gl_texture_image * texImage)54 _swrast_delete_texture_image(struct gl_context *ctx,
55                              struct gl_texture_image *texImage)
56 {
57    /* Nothing special for the subclass yet */
58    _mesa_delete_texture_image(ctx, texImage);
59 }
60 
61 
62 /**
63  * Called via ctx->Driver.AllocTextureImageBuffer()
64  */
65 GLboolean
_swrast_alloc_texture_image_buffer(struct gl_context * ctx,struct gl_texture_image * texImage)66 _swrast_alloc_texture_image_buffer(struct gl_context *ctx,
67                                    struct gl_texture_image *texImage)
68 {
69    struct swrast_texture_image *swImg = swrast_texture_image(texImage);
70    GLuint bytes = _mesa_format_image_size(texImage->TexFormat, texImage->Width,
71                                           texImage->Height, texImage->Depth);
72    GLuint i;
73 
74    assert(!swImg->Buffer);
75    swImg->Buffer = _mesa_align_malloc(bytes, 512);
76    if (!swImg->Buffer)
77       return GL_FALSE;
78 
79    /* RowStride and ImageOffsets[] describe how to address texels in 'Data' */
80    swImg->RowStride = texImage->Width;
81 
82    /* Allocate the ImageOffsets array and initialize to typical values.
83     * We allocate the array for 1D/2D textures too in order to avoid special-
84     * case code in the texstore routines.
85     */
86    swImg->ImageOffsets = (GLuint *) malloc(texImage->Depth * sizeof(GLuint));
87    if (!swImg->ImageOffsets)
88       return GL_FALSE;
89 
90    for (i = 0; i < texImage->Depth; i++) {
91       swImg->ImageOffsets[i] = i * texImage->Width * texImage->Height;
92    }
93 
94    _swrast_init_texture_image(texImage);
95 
96    return GL_TRUE;
97 }
98 
99 
100 /**
101  * Code that overrides ctx->Driver.AllocTextureImageBuffer may use this to
102  * initialize the fields of swrast_texture_image without allocating the image
103  * buffer or initializing ImageOffsets or RowStride.
104  *
105  * Returns GL_TRUE on success, GL_FALSE on memory allocation failure.
106  */
107 void
_swrast_init_texture_image(struct gl_texture_image * texImage)108 _swrast_init_texture_image(struct gl_texture_image *texImage)
109 {
110    struct swrast_texture_image *swImg = swrast_texture_image(texImage);
111 
112    if ((texImage->Width == 1 || _mesa_is_pow_two(texImage->Width2)) &&
113        (texImage->Height == 1 || _mesa_is_pow_two(texImage->Height2)) &&
114        (texImage->Depth == 1 || _mesa_is_pow_two(texImage->Depth2)))
115       swImg->_IsPowerOfTwo = GL_TRUE;
116    else
117       swImg->_IsPowerOfTwo = GL_FALSE;
118 
119    /* Compute Width/Height/DepthScale for mipmap lod computation */
120    if (texImage->TexObject->Target == GL_TEXTURE_RECTANGLE_NV) {
121       /* scale = 1.0 since texture coords directly map to texels */
122       swImg->WidthScale = 1.0;
123       swImg->HeightScale = 1.0;
124       swImg->DepthScale = 1.0;
125    }
126    else {
127       swImg->WidthScale = (GLfloat) texImage->Width;
128       swImg->HeightScale = (GLfloat) texImage->Height;
129       swImg->DepthScale = (GLfloat) texImage->Depth;
130    }
131 }
132 
133 
134 /**
135  * Called via ctx->Driver.FreeTextureImageBuffer()
136  */
137 void
_swrast_free_texture_image_buffer(struct gl_context * ctx,struct gl_texture_image * texImage)138 _swrast_free_texture_image_buffer(struct gl_context *ctx,
139                                   struct gl_texture_image *texImage)
140 {
141    struct swrast_texture_image *swImage = swrast_texture_image(texImage);
142    if (swImage->Buffer) {
143       _mesa_align_free(swImage->Buffer);
144       swImage->Buffer = NULL;
145    }
146 
147    if (swImage->ImageOffsets) {
148       free(swImage->ImageOffsets);
149       swImage->ImageOffsets = NULL;
150    }
151 }
152 
153 
154 /**
155  * Error checking for debugging only.
156  */
157 static void
_mesa_check_map_teximage(struct gl_texture_image * texImage,GLuint slice,GLuint x,GLuint y,GLuint w,GLuint h)158 _mesa_check_map_teximage(struct gl_texture_image *texImage,
159                          GLuint slice, GLuint x, GLuint y, GLuint w, GLuint h)
160 {
161 
162    if (texImage->TexObject->Target == GL_TEXTURE_1D)
163       assert(y == 0 && h == 1);
164 
165    assert(x < texImage->Width || texImage->Width == 0);
166    assert(y < texImage->Height || texImage->Height == 0);
167    assert(x + w <= texImage->Width);
168    assert(y + h <= texImage->Height);
169 }
170 
171 /**
172  * Map a 2D slice of a texture image into user space.
173  * (x,y,w,h) defines a region of interest (ROI).  Reading/writing texels
174  * outside of the ROI is undefined.
175  *
176  * \param texImage  the texture image
177  * \param slice  the 3D image slice or array texture slice
178  * \param x, y, w, h  region of interest
179  * \param mode  bitmask of GL_MAP_READ_BIT, GL_MAP_WRITE_BIT
180  * \param mapOut  returns start of mapping of region of interest
181  * \param rowStrideOut  returns row stride (in bytes)
182  */
183 void
_swrast_map_teximage(struct gl_context * ctx,struct gl_texture_image * texImage,GLuint slice,GLuint x,GLuint y,GLuint w,GLuint h,GLbitfield mode,GLubyte ** mapOut,GLint * rowStrideOut)184 _swrast_map_teximage(struct gl_context *ctx,
185                      struct gl_texture_image *texImage,
186                      GLuint slice,
187                      GLuint x, GLuint y, GLuint w, GLuint h,
188                      GLbitfield mode,
189                      GLubyte **mapOut,
190                      GLint *rowStrideOut)
191 {
192    struct swrast_texture_image *swImage = swrast_texture_image(texImage);
193    GLubyte *map;
194    GLint stride, texelSize;
195    GLuint bw, bh;
196 
197    _mesa_check_map_teximage(texImage, slice, x, y, w, h);
198 
199    texelSize = _mesa_get_format_bytes(texImage->TexFormat);
200    stride = _mesa_format_row_stride(texImage->TexFormat, texImage->Width);
201    _mesa_get_format_block_size(texImage->TexFormat, &bw, &bh);
202 
203    assert(x % bw == 0);
204    assert(y % bh == 0);
205 
206    if (!swImage->Buffer) {
207       /* probably ran out of memory when allocating tex mem */
208       *mapOut = NULL;
209       return;
210    }
211 
212    map = swImage->Buffer;
213 
214    if (texImage->TexObject->Target == GL_TEXTURE_3D ||
215        texImage->TexObject->Target == GL_TEXTURE_2D_ARRAY) {
216       GLuint sliceSize = _mesa_format_image_size(texImage->TexFormat,
217                                                  texImage->Width,
218                                                  texImage->Height,
219                                                  1);
220       assert(slice < texImage->Depth);
221       map += slice * sliceSize;
222    } else if (texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY) {
223       GLuint sliceSize = _mesa_format_image_size(texImage->TexFormat,
224                                                  texImage->Width,
225                                                  1,
226                                                  1);
227       assert(slice < texImage->Height);
228       map += slice * sliceSize;
229    }
230 
231    /* apply x/y offset to map address */
232    map += stride * (y / bh) + texelSize * (x / bw);
233 
234    *mapOut = map;
235    *rowStrideOut = stride;
236 }
237 
238 void
_swrast_unmap_teximage(struct gl_context * ctx,struct gl_texture_image * texImage,GLuint slice)239 _swrast_unmap_teximage(struct gl_context *ctx,
240                        struct gl_texture_image *texImage,
241                        GLuint slice)
242 {
243    /* nop */
244 }
245 
246 
247 void
_swrast_map_texture(struct gl_context * ctx,struct gl_texture_object * texObj)248 _swrast_map_texture(struct gl_context *ctx, struct gl_texture_object *texObj)
249 {
250    const GLuint faces = _mesa_num_tex_faces(texObj->Target);
251    GLuint face, level;
252 
253    for (face = 0; face < faces; face++) {
254       for (level = texObj->BaseLevel; level < MAX_TEXTURE_LEVELS; level++) {
255          struct gl_texture_image *texImage = texObj->Image[face][level];
256          if (texImage) {
257             struct swrast_texture_image *swImage =
258                swrast_texture_image(texImage);
259 
260             /* XXX we'll eventually call _swrast_map_teximage() here */
261             swImage->Map = swImage->Buffer;
262          }
263       }
264    }
265 }
266 
267 
268 void
_swrast_unmap_texture(struct gl_context * ctx,struct gl_texture_object * texObj)269 _swrast_unmap_texture(struct gl_context *ctx, struct gl_texture_object *texObj)
270 {
271    const GLuint faces = _mesa_num_tex_faces(texObj->Target);
272    GLuint face, level;
273 
274    for (face = 0; face < faces; face++) {
275       for (level = texObj->BaseLevel; level < MAX_TEXTURE_LEVELS; level++) {
276          struct gl_texture_image *texImage = texObj->Image[face][level];
277          if (texImage) {
278             struct swrast_texture_image *swImage
279                = swrast_texture_image(texImage);
280 
281             /* XXX we'll eventually call _swrast_unmap_teximage() here */
282             swImage->Map = NULL;
283          }
284       }
285    }
286 }
287 
288 
289 /**
290  * Map all textures for reading prior to software rendering.
291  */
292 void
_swrast_map_textures(struct gl_context * ctx)293 _swrast_map_textures(struct gl_context *ctx)
294 {
295    GLbitfield enabledUnits = ctx->Texture._EnabledUnits;
296 
297    /* loop over enabled texture units */
298    while (enabledUnits) {
299       GLuint unit = ffs(enabledUnits) - 1;
300       struct gl_texture_object *texObj = ctx->Texture.Unit[unit]._Current;
301 
302       _swrast_map_texture(ctx, texObj);
303 
304       enabledUnits &= ~(1 << unit);
305    }
306 }
307 
308 
309 /**
310  * Unmap all textures for reading prior to software rendering.
311  */
312 void
_swrast_unmap_textures(struct gl_context * ctx)313 _swrast_unmap_textures(struct gl_context *ctx)
314 {
315    GLbitfield enabledUnits = ctx->Texture._EnabledUnits;
316 
317    /* loop over enabled texture units */
318    while (enabledUnits) {
319       GLuint unit = ffs(enabledUnits) - 1;
320       struct gl_texture_object *texObj = ctx->Texture.Unit[unit]._Current;
321 
322       _swrast_unmap_texture(ctx, texObj);
323 
324       enabledUnits &= ~(1 << unit);
325    }
326 }
327 
328 
329 /**
330  * Called via ctx->Driver.AllocTextureStorage()
331  * Just have to allocate memory for the texture images.
332  */
333 GLboolean
_swrast_AllocTextureStorage(struct gl_context * ctx,struct gl_texture_object * texObj,GLsizei levels,GLsizei width,GLsizei height,GLsizei depth)334 _swrast_AllocTextureStorage(struct gl_context *ctx,
335                             struct gl_texture_object *texObj,
336                             GLsizei levels, GLsizei width,
337                             GLsizei height, GLsizei depth)
338 {
339    const GLint numFaces = (texObj->Target == GL_TEXTURE_CUBE_MAP) ? 6 : 1;
340    GLint face, level;
341 
342    for (face = 0; face < numFaces; face++) {
343       for (level = 0; level < levels; level++) {
344          struct gl_texture_image *texImage = texObj->Image[face][level];
345          if (!_swrast_alloc_texture_image_buffer(ctx, texImage)) {
346             return GL_FALSE;
347          }
348       }
349    }
350 
351    return GL_TRUE;
352 }
353 
354