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 */
41struct gl_texture_image *
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 */
53void
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 */
65GLboolean
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 */
107void
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 */
137void
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 */
157static void
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 */
183void
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
238void
239_swrast_unmap_teximage(struct gl_context *ctx,
240                       struct gl_texture_image *texImage,
241                       GLuint slice)
242{
243   /* nop */
244}
245
246
247void
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
268void
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 */
292void
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 */
312void
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 */
333GLboolean
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