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 "util/u_memory.h"
35 #include "util/u_math.h"
36 #include "swrast/swrast.h"
37 #include "swrast/s_context.h"
38
39
40 /**
41 * Allocate a new swrast_texture_image (a subclass of gl_texture_image).
42 * Called via ctx->Driver.NewTextureImage().
43 */
44 struct gl_texture_image *
_swrast_new_texture_image(struct gl_context * ctx)45 _swrast_new_texture_image( struct gl_context *ctx )
46 {
47 (void) ctx;
48 return (struct gl_texture_image *) CALLOC_STRUCT(swrast_texture_image);
49 }
50
51
52 /**
53 * Free a swrast_texture_image (a subclass of gl_texture_image).
54 * Called via ctx->Driver.DeleteTextureImage().
55 */
56 void
_swrast_delete_texture_image(struct gl_context * ctx,struct gl_texture_image * texImage)57 _swrast_delete_texture_image(struct gl_context *ctx,
58 struct gl_texture_image *texImage)
59 {
60 /* Nothing special for the subclass yet */
61 _mesa_delete_texture_image(ctx, texImage);
62 }
63
64 static unsigned int
texture_slices(const struct gl_texture_image * texImage)65 texture_slices(const struct gl_texture_image *texImage)
66 {
67 if (texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY)
68 return texImage->Height;
69 else
70 return texImage->Depth;
71 }
72
73 unsigned int
_swrast_teximage_slice_height(struct gl_texture_image * texImage)74 _swrast_teximage_slice_height(struct gl_texture_image *texImage)
75 {
76 /* For 1D array textures, the slices are all 1 pixel high, and Height is
77 * the number of slices.
78 */
79 if (texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY)
80 return 1;
81 else
82 return texImage->Height;
83 }
84
85 /**
86 * Called via ctx->Driver.AllocTextureImageBuffer()
87 */
88 GLboolean
_swrast_alloc_texture_image_buffer(struct gl_context * ctx,struct gl_texture_image * texImage)89 _swrast_alloc_texture_image_buffer(struct gl_context *ctx,
90 struct gl_texture_image *texImage)
91 {
92 struct swrast_texture_image *swImg = swrast_texture_image(texImage);
93 GLuint bytesPerSlice;
94 GLuint slices = texture_slices(texImage);
95 GLuint i;
96
97 if (!_swrast_init_texture_image(texImage))
98 return GL_FALSE;
99
100 bytesPerSlice = _mesa_format_image_size(texImage->TexFormat, texImage->Width,
101 _swrast_teximage_slice_height(texImage), 1);
102
103 assert(!swImg->Buffer);
104 swImg->Buffer = align_malloc(bytesPerSlice * slices, 512);
105 if (!swImg->Buffer)
106 return GL_FALSE;
107
108 /* RowStride and ImageSlices[] describe how to address texels in 'Data' */
109 swImg->RowStride = _mesa_format_row_stride(texImage->TexFormat,
110 texImage->Width);
111
112 for (i = 0; i < slices; i++) {
113 swImg->ImageSlices[i] = swImg->Buffer + bytesPerSlice * i;
114 }
115
116 return GL_TRUE;
117 }
118
119
120 /**
121 * Code that overrides ctx->Driver.AllocTextureImageBuffer may use this to
122 * initialize the fields of swrast_texture_image without allocating the image
123 * buffer or initializing RowStride or the contents of ImageSlices.
124 *
125 * Returns GL_TRUE on success, GL_FALSE on memory allocation failure.
126 */
127 GLboolean
_swrast_init_texture_image(struct gl_texture_image * texImage)128 _swrast_init_texture_image(struct gl_texture_image *texImage)
129 {
130 struct swrast_texture_image *swImg = swrast_texture_image(texImage);
131
132 if ((texImage->Width == 1 || util_is_power_of_two_or_zero(texImage->Width2)) &&
133 (texImage->Height == 1 || util_is_power_of_two_or_zero(texImage->Height2)) &&
134 (texImage->Depth == 1 || util_is_power_of_two_or_zero(texImage->Depth2)))
135 swImg->_IsPowerOfTwo = GL_TRUE;
136 else
137 swImg->_IsPowerOfTwo = GL_FALSE;
138
139 /* Compute Width/Height/DepthScale for mipmap lod computation */
140 if (texImage->TexObject->Target == GL_TEXTURE_RECTANGLE_NV) {
141 /* scale = 1.0 since texture coords directly map to texels */
142 swImg->WidthScale = 1.0;
143 swImg->HeightScale = 1.0;
144 swImg->DepthScale = 1.0;
145 }
146 else {
147 swImg->WidthScale = (GLfloat) texImage->Width;
148 swImg->HeightScale = (GLfloat) texImage->Height;
149 swImg->DepthScale = (GLfloat) texImage->Depth;
150 }
151
152 assert(!swImg->ImageSlices);
153 swImg->ImageSlices = calloc(texture_slices(texImage), sizeof(void *));
154 if (!swImg->ImageSlices)
155 return GL_FALSE;
156
157 return GL_TRUE;
158 }
159
160
161 /**
162 * Called via ctx->Driver.FreeTextureImageBuffer()
163 */
164 void
_swrast_free_texture_image_buffer(struct gl_context * ctx,struct gl_texture_image * texImage)165 _swrast_free_texture_image_buffer(struct gl_context *ctx,
166 struct gl_texture_image *texImage)
167 {
168 struct swrast_texture_image *swImage = swrast_texture_image(texImage);
169
170 align_free(swImage->Buffer);
171 swImage->Buffer = NULL;
172
173 free(swImage->ImageSlices);
174 swImage->ImageSlices = NULL;
175 }
176
177
178 /**
179 * Error checking for debugging only.
180 */
181 static void
check_map_teximage(const struct gl_texture_image * texImage,GLuint slice,GLuint x,GLuint y,GLuint w,GLuint h)182 check_map_teximage(const struct gl_texture_image *texImage,
183 GLuint slice, GLuint x, GLuint y, GLuint w, GLuint h)
184 {
185
186 if (texImage->TexObject->Target == GL_TEXTURE_1D)
187 assert(y == 0 && h == 1);
188
189 assert(x < texImage->Width || texImage->Width == 0);
190 assert(y < texImage->Height || texImage->Height == 0);
191 assert(x + w <= texImage->Width);
192 assert(y + h <= texImage->Height);
193 assert(slice < texture_slices(texImage));
194 }
195
196 /**
197 * Map a 2D slice of a texture image into user space.
198 * (x,y,w,h) defines a region of interest (ROI). Reading/writing texels
199 * outside of the ROI is undefined.
200 *
201 * \param texImage the texture image
202 * \param slice the 3D image slice or array texture slice
203 * \param x, y, w, h region of interest
204 * \param mode bitmask of GL_MAP_READ_BIT, GL_MAP_WRITE_BIT
205 * \param mapOut returns start of mapping of region of interest
206 * \param rowStrideOut returns row stride (in bytes)
207 */
208 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)209 _swrast_map_teximage(struct gl_context *ctx,
210 struct gl_texture_image *texImage,
211 GLuint slice,
212 GLuint x, GLuint y, GLuint w, GLuint h,
213 GLbitfield mode,
214 GLubyte **mapOut,
215 GLint *rowStrideOut)
216 {
217 struct swrast_texture_image *swImage = swrast_texture_image(texImage);
218 GLubyte *map;
219 GLint stride, texelSize;
220 GLuint bw, bh;
221
222 check_map_teximage(texImage, slice, x, y, w, h);
223
224 if (!swImage->Buffer) {
225 /* Either glTexImage was called with a NULL <pixels> argument or
226 * we ran out of memory when allocating texture memory,
227 */
228 *mapOut = NULL;
229 *rowStrideOut = 0;
230 return;
231 }
232
233 texelSize = _mesa_get_format_bytes(texImage->TexFormat);
234 stride = _mesa_format_row_stride(texImage->TexFormat, texImage->Width);
235 _mesa_get_format_block_size(texImage->TexFormat, &bw, &bh);
236
237 assert(x % bw == 0);
238 assert(y % bh == 0);
239
240 /* This function can only be used with a swrast-allocated buffer, in which
241 * case ImageSlices is populated with pointers into Buffer.
242 */
243 assert(swImage->Buffer);
244 assert(swImage->Buffer == swImage->ImageSlices[0]);
245
246 map = swImage->ImageSlices[slice];
247
248 /* apply x/y offset to map address */
249 map += stride * (y / bh) + texelSize * (x / bw);
250
251 *mapOut = map;
252 *rowStrideOut = stride;
253 }
254
255 void
_swrast_unmap_teximage(struct gl_context * ctx,struct gl_texture_image * texImage,GLuint slice)256 _swrast_unmap_teximage(struct gl_context *ctx,
257 struct gl_texture_image *texImage,
258 GLuint slice)
259 {
260 /* nop */
261 }
262
263
264 void
_swrast_map_texture(struct gl_context * ctx,struct gl_texture_object * texObj)265 _swrast_map_texture(struct gl_context *ctx, struct gl_texture_object *texObj)
266 {
267 const GLuint faces = _mesa_num_tex_faces(texObj->Target);
268 GLuint face, level;
269
270 for (face = 0; face < faces; face++) {
271 for (level = texObj->BaseLevel; level < MAX_TEXTURE_LEVELS; level++) {
272 struct gl_texture_image *texImage = texObj->Image[face][level];
273 struct swrast_texture_image *swImage = swrast_texture_image(texImage);
274 unsigned int i, slices;
275
276 if (!texImage)
277 continue;
278
279 /* In the case of a swrast-allocated texture buffer, the ImageSlices
280 * and RowStride are always available.
281 */
282 if (swImage->Buffer) {
283 assert(swImage->ImageSlices[0] == swImage->Buffer);
284 continue;
285 }
286
287 if (!swImage->ImageSlices) {
288 swImage->ImageSlices =
289 calloc(texture_slices(texImage), sizeof(void *));
290 if (!swImage->ImageSlices)
291 continue;
292 }
293
294 slices = texture_slices(texImage);
295
296 for (i = 0; i < slices; i++) {
297 GLubyte *map;
298 GLint rowStride;
299
300 if (swImage->ImageSlices[i])
301 continue;
302
303 ctx->Driver.MapTextureImage(ctx, texImage, i,
304 0, 0,
305 texImage->Width, texImage->Height,
306 GL_MAP_READ_BIT | GL_MAP_WRITE_BIT,
307 &map, &rowStride);
308
309 swImage->ImageSlices[i] = map;
310 /* A swrast-using driver has to return the same rowstride for
311 * every slice of the same texture, since we don't track them
312 * separately.
313 */
314 if (i == 0)
315 swImage->RowStride = rowStride;
316 else
317 assert(swImage->RowStride == rowStride);
318 }
319 }
320 }
321 }
322
323
324 void
_swrast_unmap_texture(struct gl_context * ctx,struct gl_texture_object * texObj)325 _swrast_unmap_texture(struct gl_context *ctx, struct gl_texture_object *texObj)
326 {
327 const GLuint faces = _mesa_num_tex_faces(texObj->Target);
328 GLuint face, level;
329
330 for (face = 0; face < faces; face++) {
331 for (level = texObj->BaseLevel; level < MAX_TEXTURE_LEVELS; level++) {
332 struct gl_texture_image *texImage = texObj->Image[face][level];
333 struct swrast_texture_image *swImage = swrast_texture_image(texImage);
334 unsigned int i, slices;
335
336 if (!texImage)
337 continue;
338
339 if (swImage->Buffer)
340 return;
341
342 if (!swImage->ImageSlices)
343 continue;
344
345 slices = texture_slices(texImage);
346
347 for (i = 0; i < slices; i++) {
348 if (swImage->ImageSlices[i]) {
349 ctx->Driver.UnmapTextureImage(ctx, texImage, i);
350 swImage->ImageSlices[i] = NULL;
351 }
352 }
353 }
354 }
355 }
356
357
358 /**
359 * Map all textures for reading prior to software rendering.
360 */
361 void
_swrast_map_textures(struct gl_context * ctx)362 _swrast_map_textures(struct gl_context *ctx)
363 {
364 int unit;
365
366 for (unit = 0; unit <= ctx->Texture._MaxEnabledTexImageUnit; unit++) {
367 struct gl_texture_object *texObj = ctx->Texture.Unit[unit]._Current;
368
369 if (texObj)
370 _swrast_map_texture(ctx, texObj);
371 }
372 }
373
374
375 /**
376 * Unmap all textures for reading prior to software rendering.
377 */
378 void
_swrast_unmap_textures(struct gl_context * ctx)379 _swrast_unmap_textures(struct gl_context *ctx)
380 {
381 int unit;
382 for (unit = 0; unit <= ctx->Texture._MaxEnabledTexImageUnit; unit++) {
383 struct gl_texture_object *texObj = ctx->Texture.Unit[unit]._Current;
384
385 if (texObj)
386 _swrast_unmap_texture(ctx, texObj);
387 }
388 }
389