f945a6b0fa8dd2766923f345cd576a1b2fe27472
[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 "swrast/swrast.h"
33 #include "swrast/s_context.h"
34
35
36 /**
37 * Allocate a new swrast_texture_image (a subclass of gl_texture_image).
38 * Called via ctx->Driver.NewTextureImage().
39 */
40 struct gl_texture_image *
41 _swrast_new_texture_image( struct gl_context *ctx )
42 {
43 (void) ctx;
44 return (struct gl_texture_image *) CALLOC_STRUCT(swrast_texture_image);
45 }
46
47
48 /**
49 * Free a swrast_texture_image (a subclass of gl_texture_image).
50 * Called via ctx->Driver.DeleteTextureImage().
51 */
52 void
53 _swrast_delete_texture_image(struct gl_context *ctx,
54 struct gl_texture_image *texImage)
55 {
56 /* Nothing special for the subclass yet */
57 _mesa_delete_texture_image(ctx, texImage);
58 }
59
60
61 /**
62 * Called via ctx->Driver.AllocTextureImageBuffer()
63 */
64 GLboolean
65 _swrast_alloc_texture_image_buffer(struct gl_context *ctx,
66 struct gl_texture_image *texImage,
67 gl_format format, GLsizei width,
68 GLsizei height, GLsizei depth)
69 {
70 struct swrast_texture_image *swImg = swrast_texture_image(texImage);
71 GLuint bytes = _mesa_format_image_size(format, width, height, depth);
72 GLuint i;
73
74 /* This _should_ be true (revisit if these ever fail) */
75 assert(texImage->Width == width);
76 assert(texImage->Height == height);
77 assert(texImage->Depth == depth);
78
79 assert(!swImg->Buffer);
80 swImg->Buffer = _mesa_align_malloc(bytes, 512);
81 if (!swImg->Buffer)
82 return GL_FALSE;
83
84 /* RowStride and ImageOffsets[] describe how to address texels in 'Data' */
85 swImg->RowStride = width;
86
87 /* Allocate the ImageOffsets array and initialize to typical values.
88 * We allocate the array for 1D/2D textures too in order to avoid special-
89 * case code in the texstore routines.
90 */
91 swImg->ImageOffsets = (GLuint *) malloc(depth * sizeof(GLuint));
92 if (!swImg->ImageOffsets)
93 return GL_FALSE;
94
95 for (i = 0; i < depth; i++) {
96 swImg->ImageOffsets[i] = i * width * height;
97 }
98
99 if ((width == 1 || _mesa_is_pow_two(texImage->Width2)) &&
100 (height == 1 || _mesa_is_pow_two(texImage->Height2)) &&
101 (depth == 1 || _mesa_is_pow_two(texImage->Depth2)))
102 swImg->_IsPowerOfTwo = GL_TRUE;
103 else
104 swImg->_IsPowerOfTwo = GL_FALSE;
105
106 /* Compute Width/Height/DepthScale for mipmap lod computation */
107 if (texImage->TexObject->Target == GL_TEXTURE_RECTANGLE_NV) {
108 /* scale = 1.0 since texture coords directly map to texels */
109 swImg->WidthScale = 1.0;
110 swImg->HeightScale = 1.0;
111 swImg->DepthScale = 1.0;
112 }
113 else {
114 swImg->WidthScale = (GLfloat) texImage->Width;
115 swImg->HeightScale = (GLfloat) texImage->Height;
116 swImg->DepthScale = (GLfloat) texImage->Depth;
117 }
118
119 return GL_TRUE;
120 }
121
122
123 /**
124 * Called via ctx->Driver.FreeTextureImageBuffer()
125 */
126 void
127 _swrast_free_texture_image_buffer(struct gl_context *ctx,
128 struct gl_texture_image *texImage)
129 {
130 struct swrast_texture_image *swImage = swrast_texture_image(texImage);
131 if (swImage->Buffer) {
132 _mesa_align_free(swImage->Buffer);
133 swImage->Buffer = NULL;
134 }
135
136 if (swImage->ImageOffsets) {
137 free(swImage->ImageOffsets);
138 swImage->ImageOffsets = NULL;
139 }
140 }
141
142
143 /**
144 * Error checking for debugging only.
145 */
146 static void
147 _mesa_check_map_teximage(struct gl_texture_image *texImage,
148 GLuint slice, GLuint x, GLuint y, GLuint w, GLuint h)
149 {
150
151 if (texImage->TexObject->Target == GL_TEXTURE_1D)
152 assert(y == 0 && h == 1);
153
154 assert(x < texImage->Width || texImage->Width == 0);
155 assert(y < texImage->Height || texImage->Height == 0);
156 assert(x + w <= texImage->Width);
157 assert(y + h <= texImage->Height);
158 }
159
160 /**
161 * Map a 2D slice of a texture image into user space.
162 * (x,y,w,h) defines a region of interest (ROI). Reading/writing texels
163 * outside of the ROI is undefined.
164 *
165 * \param texImage the texture image
166 * \param slice the 3D image slice or array texture slice
167 * \param x, y, w, h region of interest
168 * \param mode bitmask of GL_MAP_READ_BIT, GL_MAP_WRITE_BIT
169 * \param mapOut returns start of mapping of region of interest
170 * \param rowStrideOut returns row stride (in bytes)
171 */
172 void
173 _swrast_map_teximage(struct gl_context *ctx,
174 struct gl_texture_image *texImage,
175 GLuint slice,
176 GLuint x, GLuint y, GLuint w, GLuint h,
177 GLbitfield mode,
178 GLubyte **mapOut,
179 GLint *rowStrideOut)
180 {
181 struct swrast_texture_image *swImage = swrast_texture_image(texImage);
182 GLubyte *map;
183 GLint stride, texelSize;
184 GLuint bw, bh;
185
186 _mesa_check_map_teximage(texImage, slice, x, y, w, h);
187
188 texelSize = _mesa_get_format_bytes(texImage->TexFormat);
189 stride = _mesa_format_row_stride(texImage->TexFormat, texImage->Width);
190 _mesa_get_format_block_size(texImage->TexFormat, &bw, &bh);
191
192 assert(x % bw == 0);
193 assert(y % bh == 0);
194
195 if (!swImage->Buffer) {
196 /* probably ran out of memory when allocating tex mem */
197 *mapOut = NULL;
198 return;
199 }
200
201 map = swImage->Buffer;
202
203 if (texImage->TexObject->Target == GL_TEXTURE_3D ||
204 texImage->TexObject->Target == GL_TEXTURE_2D_ARRAY) {
205 GLuint sliceSize = _mesa_format_image_size(texImage->TexFormat,
206 texImage->Width,
207 texImage->Height,
208 1);
209 assert(slice < texImage->Depth);
210 map += slice * sliceSize;
211 } else if (texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY) {
212 GLuint sliceSize = _mesa_format_image_size(texImage->TexFormat,
213 texImage->Width,
214 1,
215 1);
216 assert(slice < texImage->Height);
217 map += slice * sliceSize;
218 }
219
220 /* apply x/y offset to map address */
221 map += stride * (y / bh) + texelSize * (x / bw);
222
223 *mapOut = map;
224 *rowStrideOut = stride;
225 }
226
227 void
228 _swrast_unmap_teximage(struct gl_context *ctx,
229 struct gl_texture_image *texImage,
230 GLuint slice)
231 {
232 /* nop */
233 }
234
235
236 void
237 _swrast_map_texture(struct gl_context *ctx, struct gl_texture_object *texObj)
238 {
239 const GLuint faces = texObj->Target == GL_TEXTURE_CUBE_MAP ? 6 : 1;
240 GLuint face, level;
241
242 for (face = 0; face < faces; face++) {
243 for (level = texObj->BaseLevel; level < MAX_TEXTURE_LEVELS; level++) {
244 struct gl_texture_image *texImage = texObj->Image[face][level];
245 if (texImage) {
246 struct swrast_texture_image *swImage =
247 swrast_texture_image(texImage);
248
249 /* XXX we'll eventually call _swrast_map_teximage() here */
250 swImage->Map = swImage->Buffer;
251 }
252 }
253 }
254 }
255
256
257 void
258 _swrast_unmap_texture(struct gl_context *ctx, struct gl_texture_object *texObj)
259 {
260 const GLuint faces = texObj->Target == GL_TEXTURE_CUBE_MAP ? 6 : 1;
261 GLuint face, level;
262
263 for (face = 0; face < faces; face++) {
264 for (level = texObj->BaseLevel; level < MAX_TEXTURE_LEVELS; level++) {
265 struct gl_texture_image *texImage = texObj->Image[face][level];
266 if (texImage) {
267 struct swrast_texture_image *swImage
268 = swrast_texture_image(texImage);
269
270 /* XXX we'll eventually call _swrast_unmap_teximage() here */
271 swImage->Map = NULL;
272 }
273 }
274 }
275 }
276
277
278 /**
279 * Map all textures for reading prior to software rendering.
280 */
281 void
282 _swrast_map_textures(struct gl_context *ctx)
283 {
284 GLbitfield enabledUnits = ctx->Texture._EnabledUnits;
285
286 /* loop over enabled texture units */
287 while (enabledUnits) {
288 GLuint unit = ffs(enabledUnits) - 1;
289 struct gl_texture_object *texObj = ctx->Texture.Unit[unit]._Current;
290
291 _swrast_map_texture(ctx, texObj);
292
293 enabledUnits &= ~(1 << unit);
294 }
295 }
296
297
298 /**
299 * Unmap all textures for reading prior to software rendering.
300 */
301 void
302 _swrast_unmap_textures(struct gl_context *ctx)
303 {
304 GLbitfield enabledUnits = ctx->Texture._EnabledUnits;
305
306 /* loop over enabled texture units */
307 while (enabledUnits) {
308 GLuint unit = ffs(enabledUnits) - 1;
309 struct gl_texture_object *texObj = ctx->Texture.Unit[unit]._Current;
310
311 _swrast_unmap_texture(ctx, texObj);
312
313 enabledUnits &= ~(1 << unit);
314 }
315 }
316
317
318 static void
319 map_attachment(struct gl_context *ctx,
320 struct gl_framebuffer *fb,
321 gl_buffer_index buffer)
322 {
323 struct gl_texture_object *texObj = fb->Attachment[buffer].Texture;
324 struct gl_renderbuffer *rb = fb->Attachment[buffer].Renderbuffer;
325
326 if (texObj) {
327 const GLuint level = fb->Attachment[buffer].TextureLevel;
328 const GLuint face = fb->Attachment[buffer].CubeMapFace;
329 struct gl_texture_image *texImage = texObj->Image[face][level];
330 if (texImage) {
331 struct swrast_texture_image *swImage
332 = swrast_texture_image(texImage);
333
334 /* XXX we'll eventually call _swrast_map_teximage() here */
335 swImage->Map = swImage->Buffer;
336 if (rb) {
337 rb->Map = swImage->Buffer;
338 rb->RowStrideBytes = swImage->RowStride *
339 _mesa_get_format_bytes(swImage->Base.TexFormat);
340 }
341 }
342 }
343 else if (rb) {
344 /* Map ordinary renderbuffer */
345 /* XXX don't map color buffers yet */
346 if (buffer == BUFFER_DEPTH || buffer == BUFFER_STENCIL) {
347 ctx->Driver.MapRenderbuffer(ctx, rb,
348 0, 0, rb->Width, rb->Height,
349 GL_MAP_READ_BIT | GL_MAP_WRITE_BIT,
350 &rb->Map, &rb->RowStrideBytes);
351 assert(rb->Map);
352 }
353 }
354 }
355
356
357 static void
358 unmap_attachment(struct gl_context *ctx,
359 struct gl_framebuffer *fb,
360 gl_buffer_index buffer)
361 {
362 struct gl_texture_object *texObj = fb->Attachment[buffer].Texture;
363 struct gl_renderbuffer *rb = fb->Attachment[buffer].Renderbuffer;
364
365 if (texObj) {
366 const GLuint level = fb->Attachment[buffer].TextureLevel;
367 const GLuint face = fb->Attachment[buffer].CubeMapFace;
368 struct gl_texture_image *texImage = texObj->Image[face][level];
369 if (texImage) {
370
371 /* XXX we'll eventually call _swrast_unmap_teximage() here */
372 }
373 }
374 else if (rb) {
375 /* unmap ordinary renderbuffer */
376 /* XXX don't map color buffers yet */
377 if (buffer == BUFFER_DEPTH || buffer == BUFFER_STENCIL) {
378 ctx->Driver.UnmapRenderbuffer(ctx, rb);
379 }
380 }
381
382 rb->Map = NULL;
383 rb->RowStrideBytes = 0;
384 }
385
386
387 /**
388 * Map the renderbuffers we'll use for tri/line/point rendering.
389 */
390 void
391 _swrast_map_renderbuffers(struct gl_context *ctx)
392 {
393 struct gl_framebuffer *fb = ctx->DrawBuffer;
394 struct gl_renderbuffer *depthRb, *stencilRb;
395 GLuint buf;
396
397 depthRb = fb->Attachment[BUFFER_DEPTH].Renderbuffer;
398 if (depthRb) {
399 /* map depth buffer */
400 map_attachment(ctx, fb, BUFFER_DEPTH);
401 }
402
403 stencilRb = fb->Attachment[BUFFER_STENCIL].Renderbuffer;
404 if (stencilRb && stencilRb != depthRb) {
405 /* map stencil buffer */
406 map_attachment(ctx, fb, BUFFER_STENCIL);
407 }
408
409 for (buf = 0; buf < fb->_NumColorDrawBuffers; buf++) {
410 map_attachment(ctx, fb, fb->_ColorDrawBufferIndexes[buf]);
411 }
412 }
413
414
415 /**
416 * Unmap renderbuffers after rendering.
417 */
418 void
419 _swrast_unmap_renderbuffers(struct gl_context *ctx)
420 {
421 struct gl_framebuffer *fb = ctx->DrawBuffer;
422 struct gl_renderbuffer *depthRb, *stencilRb;
423 GLuint buf;
424
425 depthRb = fb->Attachment[BUFFER_DEPTH].Renderbuffer;
426 if (depthRb) {
427 /* map depth buffer */
428 unmap_attachment(ctx, fb, BUFFER_DEPTH);
429 }
430
431 stencilRb = fb->Attachment[BUFFER_STENCIL].Renderbuffer;
432 if (stencilRb && stencilRb != depthRb) {
433 /* map stencil buffer */
434 unmap_attachment(ctx, fb, BUFFER_STENCIL);
435 }
436
437 for (buf = 0; buf < fb->_NumColorDrawBuffers; buf++) {
438 unmap_attachment(ctx, fb, fb->_ColorDrawBufferIndexes[buf]);
439 }
440 }
441
442
443
444 /**
445 * Called via ctx->Driver.AllocTextureStorage()
446 * Just have to allocate memory for the texture images.
447 */
448 GLboolean
449 _swrast_AllocTextureStorage(struct gl_context *ctx,
450 struct gl_texture_object *texObj,
451 GLsizei levels, GLsizei width,
452 GLsizei height, GLsizei depth)
453 {
454 const GLint numFaces = (texObj->Target == GL_TEXTURE_CUBE_MAP) ? 6 : 1;
455 GLint face, level;
456
457 for (face = 0; face < numFaces; face++) {
458 for (level = 0; level < levels; level++) {
459 struct gl_texture_image *texImage = texObj->Image[face][level];
460 if (!_swrast_alloc_texture_image_buffer(ctx, texImage,
461 texImage->TexFormat,
462 texImage->Width,
463 texImage->Height,
464 texImage->Depth)) {
465 return GL_FALSE;
466 }
467 }
468 }
469
470 return GL_TRUE;
471 }
472