mesa: Generalize TexStorage allocator between swrast and intel.
[mesa.git] / src / mesa / swrast / s_texture.c
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 *
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
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
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 = 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
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
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 free(swImage->ImageOffsets);
148 swImage->ImageOffsets = NULL;
149 }
150
151
152 /**
153 * Error checking for debugging only.
154 */
155 static void
156 _mesa_check_map_teximage(struct gl_texture_image *texImage,
157 GLuint slice, GLuint x, GLuint y, GLuint w, GLuint h)
158 {
159
160 if (texImage->TexObject->Target == GL_TEXTURE_1D)
161 assert(y == 0 && h == 1);
162
163 assert(x < texImage->Width || texImage->Width == 0);
164 assert(y < texImage->Height || texImage->Height == 0);
165 assert(x + w <= texImage->Width);
166 assert(y + h <= texImage->Height);
167 }
168
169 /**
170 * Map a 2D slice of a texture image into user space.
171 * (x,y,w,h) defines a region of interest (ROI). Reading/writing texels
172 * outside of the ROI is undefined.
173 *
174 * \param texImage the texture image
175 * \param slice the 3D image slice or array texture slice
176 * \param x, y, w, h region of interest
177 * \param mode bitmask of GL_MAP_READ_BIT, GL_MAP_WRITE_BIT
178 * \param mapOut returns start of mapping of region of interest
179 * \param rowStrideOut returns row stride (in bytes)
180 */
181 void
182 _swrast_map_teximage(struct gl_context *ctx,
183 struct gl_texture_image *texImage,
184 GLuint slice,
185 GLuint x, GLuint y, GLuint w, GLuint h,
186 GLbitfield mode,
187 GLubyte **mapOut,
188 GLint *rowStrideOut)
189 {
190 struct swrast_texture_image *swImage = swrast_texture_image(texImage);
191 GLubyte *map;
192 GLint stride, texelSize;
193 GLuint bw, bh;
194
195 _mesa_check_map_teximage(texImage, slice, x, y, w, h);
196
197 texelSize = _mesa_get_format_bytes(texImage->TexFormat);
198 stride = _mesa_format_row_stride(texImage->TexFormat, texImage->Width);
199 _mesa_get_format_block_size(texImage->TexFormat, &bw, &bh);
200
201 assert(x % bw == 0);
202 assert(y % bh == 0);
203
204 if (!swImage->Buffer) {
205 /* probably ran out of memory when allocating tex mem */
206 *mapOut = NULL;
207 return;
208 }
209
210 map = swImage->Buffer;
211
212 if (texImage->TexObject->Target == GL_TEXTURE_3D ||
213 texImage->TexObject->Target == GL_TEXTURE_2D_ARRAY) {
214 GLuint sliceSize = _mesa_format_image_size(texImage->TexFormat,
215 texImage->Width,
216 texImage->Height,
217 1);
218 assert(slice < texImage->Depth);
219 map += slice * sliceSize;
220 } else if (texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY) {
221 GLuint sliceSize = _mesa_format_image_size(texImage->TexFormat,
222 texImage->Width,
223 1,
224 1);
225 assert(slice < texImage->Height);
226 map += slice * sliceSize;
227 }
228
229 /* apply x/y offset to map address */
230 map += stride * (y / bh) + texelSize * (x / bw);
231
232 *mapOut = map;
233 *rowStrideOut = stride;
234 }
235
236 void
237 _swrast_unmap_teximage(struct gl_context *ctx,
238 struct gl_texture_image *texImage,
239 GLuint slice)
240 {
241 /* nop */
242 }
243
244
245 void
246 _swrast_map_texture(struct gl_context *ctx, struct gl_texture_object *texObj)
247 {
248 const GLuint faces = _mesa_num_tex_faces(texObj->Target);
249 GLuint face, level;
250
251 for (face = 0; face < faces; face++) {
252 for (level = texObj->BaseLevel; level < MAX_TEXTURE_LEVELS; level++) {
253 struct gl_texture_image *texImage = texObj->Image[face][level];
254 if (texImage) {
255 struct swrast_texture_image *swImage =
256 swrast_texture_image(texImage);
257
258 /* XXX we'll eventually call _swrast_map_teximage() here */
259 swImage->Map = swImage->Buffer;
260 }
261 }
262 }
263 }
264
265
266 void
267 _swrast_unmap_texture(struct gl_context *ctx, struct gl_texture_object *texObj)
268 {
269 const GLuint faces = _mesa_num_tex_faces(texObj->Target);
270 GLuint face, level;
271
272 for (face = 0; face < faces; face++) {
273 for (level = texObj->BaseLevel; level < MAX_TEXTURE_LEVELS; level++) {
274 struct gl_texture_image *texImage = texObj->Image[face][level];
275 if (texImage) {
276 struct swrast_texture_image *swImage
277 = swrast_texture_image(texImage);
278
279 /* XXX we'll eventually call _swrast_unmap_teximage() here */
280 swImage->Map = NULL;
281 }
282 }
283 }
284 }
285
286
287 /**
288 * Map all textures for reading prior to software rendering.
289 */
290 void
291 _swrast_map_textures(struct gl_context *ctx)
292 {
293 GLbitfield enabledUnits = ctx->Texture._EnabledUnits;
294
295 /* loop over enabled texture units */
296 while (enabledUnits) {
297 GLuint unit = ffs(enabledUnits) - 1;
298 struct gl_texture_object *texObj = ctx->Texture.Unit[unit]._Current;
299
300 _swrast_map_texture(ctx, texObj);
301
302 enabledUnits &= ~(1 << unit);
303 }
304 }
305
306
307 /**
308 * Unmap all textures for reading prior to software rendering.
309 */
310 void
311 _swrast_unmap_textures(struct gl_context *ctx)
312 {
313 GLbitfield enabledUnits = ctx->Texture._EnabledUnits;
314
315 /* loop over enabled texture units */
316 while (enabledUnits) {
317 GLuint unit = ffs(enabledUnits) - 1;
318 struct gl_texture_object *texObj = ctx->Texture.Unit[unit]._Current;
319
320 _swrast_unmap_texture(ctx, texObj);
321
322 enabledUnits &= ~(1 << unit);
323 }
324 }