Merge branch 'mesa_7_7_branch'
[mesa.git] / src / mesa / state_tracker / st_texture.c
1 /**************************************************************************
2 *
3 * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28 #include "st_context.h"
29 #include "st_format.h"
30 #include "st_public.h"
31 #include "st_texture.h"
32 #include "st_cb_fbo.h"
33 #include "st_inlines.h"
34 #include "main/enums.h"
35 #include "main/texfetch.h"
36 #include "main/teximage.h"
37 #include "main/texobj.h"
38 #include "main/texstore.h"
39
40 #undef Elements /* fix re-defined macro warning */
41
42 #include "pipe/p_state.h"
43 #include "pipe/p_context.h"
44 #include "pipe/p_defines.h"
45 #include "pipe/p_inlines.h"
46 #include "util/u_format.h"
47 #include "util/u_rect.h"
48 #include "util/u_math.h"
49
50
51 #define DBG if(0) printf
52
53 #if 0
54 static GLenum
55 target_to_target(GLenum target)
56 {
57 switch (target) {
58 case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB:
59 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB:
60 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB:
61 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB:
62 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB:
63 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB:
64 return GL_TEXTURE_CUBE_MAP_ARB;
65 default:
66 return target;
67 }
68 }
69 #endif
70
71
72 /**
73 * Allocate a new pipe_texture object
74 * width0, height0, depth0 are the dimensions of the level 0 image
75 * (the highest resolution). last_level indicates how many mipmap levels
76 * to allocate storage for. For non-mipmapped textures, this will be zero.
77 */
78 struct pipe_texture *
79 st_texture_create(struct st_context *st,
80 enum pipe_texture_target target,
81 enum pipe_format format,
82 GLuint last_level,
83 GLuint width0,
84 GLuint height0,
85 GLuint depth0,
86 GLuint usage )
87 {
88 struct pipe_texture pt, *newtex;
89 struct pipe_screen *screen = st->pipe->screen;
90
91 assert(target <= PIPE_TEXTURE_CUBE);
92
93 DBG("%s target %s format %s last_level %d\n", __FUNCTION__,
94 _mesa_lookup_enum_by_nr(target),
95 _mesa_lookup_enum_by_nr(format), last_level);
96
97 assert(format);
98 assert(screen->is_format_supported(screen, format, target,
99 PIPE_TEXTURE_USAGE_SAMPLER, 0));
100
101 memset(&pt, 0, sizeof(pt));
102 pt.target = target;
103 pt.format = format;
104 pt.last_level = last_level;
105 pt.width0 = width0;
106 pt.height0 = height0;
107 pt.depth0 = depth0;
108 pt.tex_usage = usage;
109
110 newtex = screen->texture_create(screen, &pt);
111
112 assert(!newtex || pipe_is_referenced(&newtex->reference));
113
114 return newtex;
115 }
116
117
118 /**
119 * Check if a texture image can be pulled into a unified mipmap texture.
120 */
121 GLboolean
122 st_texture_match_image(const struct pipe_texture *pt,
123 const struct gl_texture_image *image,
124 GLuint face, GLuint level)
125 {
126 /* Images with borders are never pulled into mipmap textures.
127 */
128 if (image->Border)
129 return GL_FALSE;
130
131 /* Check if this image's format matches the established texture's format.
132 */
133 if (st_mesa_format_to_pipe_format(image->TexFormat) != pt->format)
134 return GL_FALSE;
135
136 /* Test if this image's size matches what's expected in the
137 * established texture.
138 */
139 if (image->Width != u_minify(pt->width0, level) ||
140 image->Height != u_minify(pt->height0, level) ||
141 image->Depth != u_minify(pt->depth0, level))
142 return GL_FALSE;
143
144 return GL_TRUE;
145 }
146
147
148 #if 000
149 /* Although we use the image_offset[] array to store relative offsets
150 * to cube faces, Mesa doesn't know anything about this and expects
151 * each cube face to be treated as a separate image.
152 *
153 * These functions present that view to mesa:
154 */
155 const GLuint *
156 st_texture_depth_offsets(struct pipe_texture *pt, GLuint level)
157 {
158 static const GLuint zero = 0;
159
160 if (pt->target != PIPE_TEXTURE_3D || pt->level[level].nr_images == 1)
161 return &zero;
162 else
163 return pt->level[level].image_offset;
164 }
165
166
167 /**
168 * Return the offset to the given mipmap texture image within the
169 * texture memory buffer, in bytes.
170 */
171 GLuint
172 st_texture_image_offset(const struct pipe_texture * pt,
173 GLuint face, GLuint level)
174 {
175 if (pt->target == PIPE_TEXTURE_CUBE)
176 return (pt->level[level].level_offset +
177 pt->level[level].image_offset[face] * pt->cpp);
178 else
179 return pt->level[level].level_offset;
180 }
181 #endif
182
183
184 /**
185 * Map a teximage in a mipmap texture.
186 * \param row_stride returns row stride in bytes
187 * \param image_stride returns image stride in bytes (for 3D textures).
188 * \return address of mapping
189 */
190 GLubyte *
191 st_texture_image_map(struct st_context *st, struct st_texture_image *stImage,
192 GLuint zoffset, enum pipe_transfer_usage usage,
193 GLuint x, GLuint y, GLuint w, GLuint h)
194 {
195 struct pipe_context *pipe = st->pipe;
196 struct pipe_screen *screen = pipe->screen;
197 struct pipe_texture *pt = stImage->pt;
198
199 DBG("%s \n", __FUNCTION__);
200
201 stImage->transfer = st_no_flush_get_tex_transfer(st, pt, stImage->face,
202 stImage->level, zoffset,
203 usage, x, y, w, h);
204
205 if (stImage->transfer)
206 return screen->transfer_map(screen, stImage->transfer);
207 else
208 return NULL;
209 }
210
211
212 void
213 st_texture_image_unmap(struct st_context *st,
214 struct st_texture_image *stImage)
215 {
216 struct pipe_screen *screen = st->pipe->screen;
217
218 DBG("%s\n", __FUNCTION__);
219
220 screen->transfer_unmap(screen, stImage->transfer);
221
222 screen->tex_transfer_destroy(stImage->transfer);
223 }
224
225
226
227 /**
228 * Upload data to a rectangular sub-region. Lots of choices how to do this:
229 *
230 * - memcpy by span to current destination
231 * - upload data as new buffer and blit
232 *
233 * Currently always memcpy.
234 */
235 static void
236 st_surface_data(struct pipe_context *pipe,
237 struct pipe_transfer *dst,
238 unsigned dstx, unsigned dsty,
239 const void *src, unsigned src_stride,
240 unsigned srcx, unsigned srcy, unsigned width, unsigned height)
241 {
242 struct pipe_screen *screen = pipe->screen;
243 void *map = screen->transfer_map(screen, dst);
244
245 assert(dst->texture);
246 util_copy_rect(map,
247 dst->texture->format,
248 dst->stride,
249 dstx, dsty,
250 width, height,
251 src, src_stride,
252 srcx, srcy);
253
254 screen->transfer_unmap(screen, dst);
255 }
256
257
258 /* Upload data for a particular image.
259 */
260 void
261 st_texture_image_data(struct st_context *st,
262 struct pipe_texture *dst,
263 GLuint face,
264 GLuint level,
265 void *src,
266 GLuint src_row_stride, GLuint src_image_stride)
267 {
268 struct pipe_context *pipe = st->pipe;
269 struct pipe_screen *screen = pipe->screen;
270 GLuint depth = u_minify(dst->depth0, level);
271 GLuint i;
272 const GLubyte *srcUB = src;
273 struct pipe_transfer *dst_transfer;
274
275 DBG("%s\n", __FUNCTION__);
276
277 for (i = 0; i < depth; i++) {
278 dst_transfer = st_no_flush_get_tex_transfer(st, dst, face, level, i,
279 PIPE_TRANSFER_WRITE, 0, 0,
280 u_minify(dst->width0, level),
281 u_minify(dst->height0, level));
282
283 st_surface_data(pipe, dst_transfer,
284 0, 0, /* dstx, dsty */
285 srcUB,
286 src_row_stride,
287 0, 0, /* source x, y */
288 u_minify(dst->width0, level),
289 u_minify(dst->height0, level)); /* width, height */
290
291 screen->tex_transfer_destroy(dst_transfer);
292
293 srcUB += src_image_stride;
294 }
295 }
296
297
298 /* Copy mipmap image between textures
299 */
300 void
301 st_texture_image_copy(struct pipe_context *pipe,
302 struct pipe_texture *dst, GLuint dstLevel,
303 struct pipe_texture *src,
304 GLuint face)
305 {
306 struct pipe_screen *screen = pipe->screen;
307 GLuint width = u_minify(dst->width0, dstLevel);
308 GLuint height = u_minify(dst->height0, dstLevel);
309 GLuint depth = u_minify(dst->depth0, dstLevel);
310 struct pipe_surface *src_surface;
311 struct pipe_surface *dst_surface;
312 GLuint i;
313
314 for (i = 0; i < depth; i++) {
315 GLuint srcLevel;
316
317 /* find src texture level of needed size */
318 for (srcLevel = 0; srcLevel <= src->last_level; srcLevel++) {
319 if (u_minify(src->width0, srcLevel) == width &&
320 u_minify(src->height0, srcLevel) == height) {
321 break;
322 }
323 }
324 assert(u_minify(src->width0, srcLevel) == width);
325 assert(u_minify(src->height0, srcLevel) == height);
326
327 #if 0
328 {
329 src_surface = screen->get_tex_surface(screen, src, face, srcLevel, i,
330 PIPE_BUFFER_USAGE_CPU_READ);
331 ubyte *map = screen->surface_map(screen, src_surface, PIPE_BUFFER_USAGE_CPU_READ);
332 map += src_surface->width * src_surface->height * 4 / 2;
333 printf("%s center pixel: %d %d %d %d (pt %p[%d] -> %p[%d])\n",
334 __FUNCTION__,
335 map[0], map[1], map[2], map[3],
336 src, srcLevel, dst, dstLevel);
337
338 screen->surface_unmap(screen, src_surface);
339 pipe_surface_reference(&src_surface, NULL);
340 }
341 #endif
342
343 dst_surface = screen->get_tex_surface(screen, dst, face, dstLevel, i,
344 PIPE_BUFFER_USAGE_GPU_WRITE);
345
346 src_surface = screen->get_tex_surface(screen, src, face, srcLevel, i,
347 PIPE_BUFFER_USAGE_GPU_READ);
348
349 if (pipe->surface_copy) {
350 pipe->surface_copy(pipe,
351 dst_surface,
352 0, 0, /* destX, Y */
353 src_surface,
354 0, 0, /* srcX, Y */
355 width, height);
356 } else {
357 util_surface_copy(pipe, FALSE,
358 dst_surface,
359 0, 0, /* destX, Y */
360 src_surface,
361 0, 0, /* srcX, Y */
362 width, height);
363 }
364
365 pipe_surface_reference(&src_surface, NULL);
366 pipe_surface_reference(&dst_surface, NULL);
367 }
368 }
369
370
371 /**
372 * Bind a pipe surface to a texture object. After the call,
373 * the texture object is marked dirty and will be (re-)validated.
374 *
375 * If this is the first surface bound, the texture object is said to
376 * switch from normal to surface based. It will be cleared first in
377 * this case.
378 *
379 * \param ps pipe surface to be unbound
380 * \param target texture target
381 * \param level image level
382 * \param format internal format of the texture
383 */
384 int
385 st_bind_texture_surface(struct pipe_surface *ps, int target, int level,
386 enum pipe_format format)
387 {
388 GET_CURRENT_CONTEXT(ctx);
389 const GLuint unit = ctx->Texture.CurrentUnit;
390 struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
391 struct gl_texture_object *texObj;
392 struct gl_texture_image *texImage;
393 struct st_texture_object *stObj;
394 struct st_texture_image *stImage;
395 GLenum internalFormat;
396
397 switch (target) {
398 case ST_TEXTURE_2D:
399 target = GL_TEXTURE_2D;
400 break;
401 case ST_TEXTURE_RECT:
402 target = GL_TEXTURE_RECTANGLE_ARB;
403 break;
404 default:
405 return 0;
406 }
407
408 /* map pipe format to base format for now */
409 if (util_format_get_component_bits(format, UTIL_FORMAT_COLORSPACE_RGB, 3) > 0)
410 internalFormat = GL_RGBA;
411 else
412 internalFormat = GL_RGB;
413
414 texObj = _mesa_select_tex_object(ctx, texUnit, target);
415 _mesa_lock_texture(ctx, texObj);
416
417 stObj = st_texture_object(texObj);
418 /* switch to surface based */
419 if (!stObj->surface_based) {
420 _mesa_clear_texture_object(ctx, texObj);
421 stObj->surface_based = GL_TRUE;
422 }
423
424 texImage = _mesa_get_tex_image(ctx, texObj, target, level);
425 stImage = st_texture_image(texImage);
426
427 _mesa_init_teximage_fields(ctx, target, texImage,
428 ps->width, ps->height, 1, 0, internalFormat);
429 texImage->TexFormat = st_ChooseTextureFormat(ctx, internalFormat,
430 GL_RGBA, GL_UNSIGNED_BYTE);
431 _mesa_set_fetch_functions(texImage, 2);
432 pipe_texture_reference(&stImage->pt, ps->texture);
433
434 _mesa_dirty_texobj(ctx, texObj, GL_TRUE);
435 _mesa_unlock_texture(ctx, texObj);
436
437 return 1;
438 }
439
440
441 /**
442 * Unbind a pipe surface from a texture object. After the call,
443 * the texture object is marked dirty and will be (re-)validated.
444 *
445 * \param ps pipe surface to be unbound
446 * \param target texture target
447 * \param level image level
448 */
449 int
450 st_unbind_texture_surface(struct pipe_surface *ps, int target, int level)
451 {
452 GET_CURRENT_CONTEXT(ctx);
453 const GLuint unit = ctx->Texture.CurrentUnit;
454 struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
455 struct gl_texture_object *texObj;
456 struct gl_texture_image *texImage;
457 struct st_texture_object *stObj;
458 struct st_texture_image *stImage;
459
460 switch (target) {
461 case ST_TEXTURE_2D:
462 target = GL_TEXTURE_2D;
463 break;
464 case ST_TEXTURE_RECT:
465 target = GL_TEXTURE_RECTANGLE_ARB;
466 break;
467 default:
468 return 0;
469 }
470
471 texObj = _mesa_select_tex_object(ctx, texUnit, target);
472
473 _mesa_lock_texture(ctx, texObj);
474
475 texImage = _mesa_get_tex_image(ctx, texObj, target, level);
476 stObj = st_texture_object(texObj);
477 stImage = st_texture_image(texImage);
478
479 /* Make sure the pipe surface is still bound. The texture object is still
480 * considered surface based even if this is the last bound surface. */
481 if (stImage->pt == ps->texture) {
482 pipe_texture_reference(&stImage->pt, NULL);
483 _mesa_clear_texture_image(ctx, texImage);
484
485 _mesa_dirty_texobj(ctx, texObj, GL_TRUE);
486 }
487
488 _mesa_unlock_texture(ctx, texObj);
489
490 return 1;
491 }
492
493
494 /** Redirect rendering into stfb's surface to a texture image */
495 int
496 st_bind_teximage(struct st_framebuffer *stfb, uint surfIndex,
497 int target, int format, int level)
498 {
499 GET_CURRENT_CONTEXT(ctx);
500 struct st_context *st = ctx->st;
501 struct pipe_context *pipe = st->pipe;
502 struct pipe_screen *screen = pipe->screen;
503 const GLuint unit = ctx->Texture.CurrentUnit;
504 struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
505 struct gl_texture_object *texObj;
506 struct gl_texture_image *texImage;
507 struct st_texture_image *stImage;
508 struct st_renderbuffer *strb;
509 GLint face = 0, slice = 0;
510
511 assert(surfIndex <= ST_SURFACE_DEPTH);
512
513 strb = st_renderbuffer(stfb->Base.Attachment[surfIndex].Renderbuffer);
514
515 if (strb->texture_save || strb->surface_save) {
516 /* Error! */
517 return 0;
518 }
519
520 if (target == ST_TEXTURE_2D) {
521 texObj = texUnit->CurrentTex[TEXTURE_2D_INDEX];
522 texImage = _mesa_get_tex_image(ctx, texObj, GL_TEXTURE_2D, level);
523 stImage = st_texture_image(texImage);
524 }
525 else {
526 /* unsupported target */
527 return 0;
528 }
529
530 st_flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, NULL);
531
532 /* save the renderbuffer's surface/texture info */
533 pipe_texture_reference(&strb->texture_save, strb->texture);
534 pipe_surface_reference(&strb->surface_save, strb->surface);
535
536 /* plug in new surface/texture info */
537 pipe_texture_reference(&strb->texture, stImage->pt);
538 strb->surface = screen->get_tex_surface(screen, strb->texture,
539 face, level, slice,
540 (PIPE_BUFFER_USAGE_GPU_READ |
541 PIPE_BUFFER_USAGE_GPU_WRITE));
542
543 st->dirty.st |= ST_NEW_FRAMEBUFFER;
544
545 return 1;
546 }
547
548
549 /** Undo surface-to-texture binding */
550 int
551 st_release_teximage(struct st_framebuffer *stfb, uint surfIndex,
552 int target, int format, int level)
553 {
554 GET_CURRENT_CONTEXT(ctx);
555 struct st_context *st = ctx->st;
556 struct st_renderbuffer *strb;
557
558 assert(surfIndex <= ST_SURFACE_DEPTH);
559
560 strb = st_renderbuffer(stfb->Base.Attachment[surfIndex].Renderbuffer);
561
562 if (!strb->texture_save || !strb->surface_save) {
563 /* Error! */
564 return 0;
565 }
566
567 st_flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, NULL);
568
569 /* free tex surface, restore original */
570 pipe_surface_reference(&strb->surface, strb->surface_save);
571 pipe_texture_reference(&strb->texture, strb->texture_save);
572
573 pipe_surface_reference(&strb->surface_save, NULL);
574 pipe_texture_reference(&strb->texture_save, NULL);
575
576 st->dirty.st |= ST_NEW_FRAMEBUFFER;
577
578 return 1;
579 }
580
581 void
582 st_teximage_flush_before_map(struct st_context *st,
583 struct pipe_texture *pt,
584 unsigned int face,
585 unsigned int level,
586 enum pipe_transfer_usage usage)
587 {
588 struct pipe_context *pipe = st->pipe;
589 unsigned referenced =
590 pipe->is_texture_referenced(pipe, pt, face, level);
591
592 if (referenced && ((referenced & PIPE_REFERENCED_FOR_WRITE) ||
593 (usage & PIPE_TRANSFER_WRITE)))
594 st->pipe->flush(st->pipe, PIPE_FLUSH_RENDER_CACHE, NULL);
595 }