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 */
42 struct gl_texture_image *
_swrast_new_texture_image(struct gl_context * ctx)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 */
54 void
_swrast_delete_texture_image(struct gl_context * ctx,struct gl_texture_image * texImage)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
62 static unsigned int
texture_slices(const struct gl_texture_image * texImage)63 texture_slices(const 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
71 unsigned int
_swrast_teximage_slice_height(struct gl_texture_image * texImage)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 */
86 GLboolean
_swrast_alloc_texture_image_buffer(struct gl_context * ctx,struct gl_texture_image * texImage)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 */
125 GLboolean
_swrast_init_texture_image(struct gl_texture_image * texImage)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 */
162 void
_swrast_free_texture_image_buffer(struct gl_context * ctx,struct gl_texture_image * texImage)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 */
179 static void
check_map_teximage(const struct gl_texture_image * texImage,GLuint slice,GLuint x,GLuint y,GLuint w,GLuint h)180 check_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 assert(slice < texture_slices(texImage));
192 }
193
194 /**
195 * Map a 2D slice of a texture image into user space.
196 * (x,y,w,h) defines a region of interest (ROI). Reading/writing texels
197 * outside of the ROI is undefined.
198 *
199 * \param texImage the texture image
200 * \param slice the 3D image slice or array texture slice
201 * \param x, y, w, h region of interest
202 * \param mode bitmask of GL_MAP_READ_BIT, GL_MAP_WRITE_BIT
203 * \param mapOut returns start of mapping of region of interest
204 * \param rowStrideOut returns row stride (in bytes)
205 */
206 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)207 _swrast_map_teximage(struct gl_context *ctx,
208 struct gl_texture_image *texImage,
209 GLuint slice,
210 GLuint x, GLuint y, GLuint w, GLuint h,
211 GLbitfield mode,
212 GLubyte **mapOut,
213 GLint *rowStrideOut)
214 {
215 struct swrast_texture_image *swImage = swrast_texture_image(texImage);
216 GLubyte *map;
217 GLint stride, texelSize;
218 GLuint bw, bh;
219
220 check_map_teximage(texImage, slice, x, y, w, h);
221
222 if (!swImage->Buffer) {
223 /* Either glTexImage was called with a NULL <pixels> argument or
224 * we ran out of memory when allocating texture memory,
225 */
226 *mapOut = NULL;
227 *rowStrideOut = 0;
228 return;
229 }
230
231 texelSize = _mesa_get_format_bytes(texImage->TexFormat);
232 stride = _mesa_format_row_stride(texImage->TexFormat, texImage->Width);
233 _mesa_get_format_block_size(texImage->TexFormat, &bw, &bh);
234
235 assert(x % bw == 0);
236 assert(y % bh == 0);
237
238 /* This function can only be used with a swrast-allocated buffer, in which
239 * case ImageSlices is populated with pointers into Buffer.
240 */
241 assert(swImage->Buffer);
242 assert(swImage->Buffer == swImage->ImageSlices[0]);
243
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
253 void
_swrast_unmap_teximage(struct gl_context * ctx,struct gl_texture_image * texImage,GLuint slice)254 _swrast_unmap_teximage(struct gl_context *ctx,
255 struct gl_texture_image *texImage,
256 GLuint slice)
257 {
258 /* nop */
259 }
260
261
262 void
_swrast_map_texture(struct gl_context * ctx,struct gl_texture_object * texObj)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
322 void
_swrast_unmap_texture(struct gl_context * ctx,struct gl_texture_object * texObj)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 */
359 void
_swrast_map_textures(struct gl_context * ctx)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 */
376 void
_swrast_unmap_textures(struct gl_context * ctx)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