New driver for i915 as well as older i830/i845/i865 chipsets.
[mesa.git] / src / mesa / drivers / dri / i915 / intel_tex.c
1 /**************************************************************************
2 *
3 * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
4 * All Rights Reserved.
5 *
6 **************************************************************************/
7
8 #include "glheader.h"
9 #include "mtypes.h"
10 #include "imports.h"
11 #include "simple_list.h"
12 #include "enums.h"
13 #include "image.h"
14 #include "texstore.h"
15 #include "texformat.h"
16 #include "teximage.h"
17 #include "texmem.h"
18 #include "texobj.h"
19 #include "swrast/swrast.h"
20
21 #include "mm.h"
22
23 #include "intel_screen.h"
24 #include "intel_batchbuffer.h"
25 #include "intel_context.h"
26 #include "intel_tex.h"
27 #include "intel_ioctl.h"
28
29
30
31 static GLboolean
32 intelValidateClientStorage( intelContextPtr intel, GLenum target,
33 GLint internalFormat,
34 GLint srcWidth, GLint srcHeight,
35 GLenum format, GLenum type, const void *pixels,
36 const struct gl_pixelstore_attrib *packing,
37 struct gl_texture_object *texObj,
38 struct gl_texture_image *texImage)
39
40 {
41 GLcontext *ctx = &intel->ctx;
42 int texelBytes;
43
44 if (0)
45 fprintf(stderr, "intformat %s format %s type %s\n",
46 _mesa_lookup_enum_by_nr( internalFormat ),
47 _mesa_lookup_enum_by_nr( format ),
48 _mesa_lookup_enum_by_nr( type ));
49
50 if (!ctx->Unpack.ClientStorage)
51 return 0;
52
53 if (ctx->_ImageTransferState ||
54 texImage->IsCompressed ||
55 texObj->GenerateMipmap)
56 return 0;
57
58
59 /* This list is incomplete
60 */
61 switch ( internalFormat ) {
62 case GL_RGBA:
63 if ( format == GL_BGRA && type == GL_UNSIGNED_INT_8_8_8_8_REV ) {
64 texImage->TexFormat = &_mesa_texformat_argb8888;
65 texelBytes = 4;
66 }
67 else
68 return 0;
69 break;
70
71 case GL_RGB:
72 if ( format == GL_RGB && type == GL_UNSIGNED_SHORT_5_6_5 ) {
73 texImage->TexFormat = &_mesa_texformat_rgb565;
74 texelBytes = 2;
75 }
76 else
77 return 0;
78 break;
79
80 case GL_YCBCR_MESA:
81 if ( format == GL_YCBCR_MESA &&
82 type == GL_UNSIGNED_SHORT_8_8_REV_APPLE ) {
83 texImage->TexFormat = &_mesa_texformat_ycbcr_rev;
84 texelBytes = 2;
85 }
86 else if ( format == GL_YCBCR_MESA &&
87 (type == GL_UNSIGNED_SHORT_8_8_APPLE ||
88 type == GL_UNSIGNED_BYTE)) {
89 texImage->TexFormat = &_mesa_texformat_ycbcr;
90 texelBytes = 2;
91 }
92 else
93 return 0;
94 break;
95
96
97 default:
98 return 0;
99 }
100
101 /* Could deal with these packing issues, but currently don't:
102 */
103 if (packing->SkipPixels ||
104 packing->SkipRows ||
105 packing->SwapBytes ||
106 packing->LsbFirst) {
107 return 0;
108 }
109
110 {
111 GLint srcRowStride = _mesa_image_row_stride(packing, srcWidth,
112 format, type);
113
114
115 if (0)
116 fprintf(stderr, "%s: srcRowStride %d/%x\n",
117 __FUNCTION__, srcRowStride, srcRowStride);
118
119 /* Could check this later in upload, pitch restrictions could be
120 * relaxed, but would need to store the image pitch somewhere,
121 * as packing details might change before image is uploaded:
122 */
123 if (!intelIsAgpMemory( intel, pixels, srcHeight * srcRowStride ) ||
124 (srcRowStride & 63))
125 return 0;
126
127
128 /* Have validated that _mesa_transfer_teximage would be a straight
129 * memcpy at this point. NOTE: future calls to TexSubImage will
130 * overwrite the client data. This is explicitly mentioned in the
131 * extension spec.
132 */
133 texImage->Data = (void *)pixels;
134 texImage->IsClientData = GL_TRUE;
135 texImage->RowStride = srcRowStride / texelBytes;
136 return 1;
137 }
138 }
139
140
141
142 static void intelTexImage1D( GLcontext *ctx, GLenum target, GLint level,
143 GLint internalFormat,
144 GLint width, GLint border,
145 GLenum format, GLenum type, const GLvoid *pixels,
146 const struct gl_pixelstore_attrib *packing,
147 struct gl_texture_object *texObj,
148 struct gl_texture_image *texImage )
149 {
150 driTextureObject * t = (driTextureObject *) texObj->DriverData;
151
152 assert(t);
153 intelFlush( ctx );
154 driSwapOutTextureObject( t );
155
156 texImage->IsClientData = GL_FALSE;
157
158 _mesa_store_teximage1d( ctx, target, level, internalFormat,
159 width, border, format, type,
160 pixels, packing, texObj, texImage );
161
162 t->dirty_images[0] |= (1 << level);
163 }
164
165 static void intelTexSubImage1D( GLcontext *ctx,
166 GLenum target,
167 GLint level,
168 GLint xoffset,
169 GLsizei width,
170 GLenum format, GLenum type,
171 const GLvoid *pixels,
172 const struct gl_pixelstore_attrib *packing,
173 struct gl_texture_object *texObj,
174 struct gl_texture_image *texImage )
175 {
176 driTextureObject * t = (driTextureObject *) texObj->DriverData;
177
178 assert(t);
179 intelFlush( ctx );
180 driSwapOutTextureObject( t );
181
182 _mesa_store_texsubimage1d(ctx, target, level, xoffset, width,
183 format, type, pixels, packing, texObj,
184 texImage);
185 }
186
187
188 /* Handles 2D, CUBE, RECT:
189 */
190 static void intelTexImage2D( GLcontext *ctx, GLenum target, GLint level,
191 GLint internalFormat,
192 GLint width, GLint height, GLint border,
193 GLenum format, GLenum type, const GLvoid *pixels,
194 const struct gl_pixelstore_attrib *packing,
195 struct gl_texture_object *texObj,
196 struct gl_texture_image *texImage )
197 {
198 driTextureObject * t = (driTextureObject *) texObj->DriverData;
199 GLuint face;
200
201 /* which cube face or ordinary 2D image */
202 switch (target) {
203 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
204 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
205 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
206 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
207 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
208 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
209 face = (GLuint) target - (GLuint) GL_TEXTURE_CUBE_MAP_POSITIVE_X;
210 ASSERT(face < 6);
211 break;
212 default:
213 face = 0;
214 }
215
216 assert(t);
217 intelFlush( ctx );
218 driSwapOutTextureObject( t );
219 texImage->IsClientData = GL_FALSE;
220
221 if (intelValidateClientStorage( INTEL_CONTEXT(ctx), target,
222 internalFormat,
223 width, height,
224 format, type, pixels,
225 packing, texObj, texImage)) {
226 if (INTEL_DEBUG & DEBUG_TEXTURE)
227 fprintf(stderr, "%s: Using client storage\n", __FUNCTION__);
228 }
229 else {
230 _mesa_store_teximage2d( ctx, target, level, internalFormat,
231 width, height, border, format, type,
232 pixels, packing, texObj, texImage );
233
234 t->dirty_images[face] |= (1 << level);
235 }
236 }
237
238 static void intelTexSubImage2D( GLcontext *ctx,
239 GLenum target,
240 GLint level,
241 GLint xoffset, GLint yoffset,
242 GLsizei width, GLsizei height,
243 GLenum format, GLenum type,
244 const GLvoid *pixels,
245 const struct gl_pixelstore_attrib *packing,
246 struct gl_texture_object *texObj,
247 struct gl_texture_image *texImage )
248 {
249 driTextureObject * t = (driTextureObject *) texObj->DriverData;
250 GLuint face;
251
252 /* which cube face or ordinary 2D image */
253 switch (target) {
254 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
255 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
256 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
257 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
258 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
259 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
260 face = (GLuint) target - (GLuint) GL_TEXTURE_CUBE_MAP_POSITIVE_X;
261 ASSERT(face < 6);
262 break;
263 default:
264 face = 0;
265 }
266
267 if (texImage->IsClientData &&
268 (char *)pixels == (char *)texImage->Data +
269 ((xoffset + yoffset * texImage->RowStride) *
270 texImage->TexFormat->TexelBytes)) {
271
272 /* Notification only - no upload required */
273 }
274 else {
275 assert( t ); /* this _should_ be true */
276 intelFlush( ctx );
277 driSwapOutTextureObject( t );
278
279 _mesa_store_texsubimage2d(ctx, target, level, xoffset, yoffset, width,
280 height, format, type, pixels, packing, texObj,
281 texImage);
282
283 t->dirty_images[face] |= (1 << level);
284 }
285 }
286
287
288
289 static void intelTexImage3D( GLcontext *ctx, GLenum target, GLint level,
290 GLint internalFormat,
291 GLint width, GLint height, GLint depth,
292 GLint border,
293 GLenum format, GLenum type, const GLvoid *pixels,
294 const struct gl_pixelstore_attrib *packing,
295 struct gl_texture_object *texObj,
296 struct gl_texture_image *texImage )
297 {
298 driTextureObject * t = (driTextureObject *) texObj->DriverData;
299
300 assert(t);
301 driSwapOutTextureObject( t );
302 texImage->IsClientData = GL_FALSE;
303
304 _mesa_store_teximage3d(ctx, target, level, internalFormat,
305 width, height, depth, border,
306 format, type, pixels,
307 &ctx->Unpack, texObj, texImage);
308
309 t->dirty_images[0] |= (1 << level);
310 }
311
312
313 static void
314 intelTexSubImage3D( GLcontext *ctx, GLenum target, GLint level,
315 GLint xoffset, GLint yoffset, GLint zoffset,
316 GLsizei width, GLsizei height, GLsizei depth,
317 GLenum format, GLenum type,
318 const GLvoid *pixels,
319 const struct gl_pixelstore_attrib *packing,
320 struct gl_texture_object *texObj,
321 struct gl_texture_image *texImage )
322 {
323 driTextureObject * t = (driTextureObject *) texObj->DriverData;
324
325 assert( t ); /* this _should_ be true */
326 driSwapOutTextureObject( t );
327
328 _mesa_store_texsubimage3d(ctx, target, level, xoffset, yoffset, zoffset,
329 width, height, depth,
330 format, type, pixels, packing, texObj, texImage);
331
332 t->dirty_images[0] |= (1 << level);
333 }
334
335
336
337
338 static void intelDeleteTexture( GLcontext *ctx, struct gl_texture_object *tObj )
339 {
340 driTextureObject * t = (driTextureObject *) tObj->DriverData;
341
342 if ( t != NULL ) {
343 intelFlush( ctx );
344 driDestroyTextureObject( t );
345 }
346
347 /* Free mipmap images and the texture object itself */
348 _mesa_delete_texture_object(ctx, tObj);
349 }
350
351
352 static const struct gl_texture_format *
353 intelChooseTextureFormat( GLcontext *ctx, GLint internalFormat,
354 GLenum format, GLenum type )
355 {
356 intelContextPtr intel = INTEL_CONTEXT( ctx );
357 const GLboolean do32bpt = ( intel->intelScreen->cpp == 4 &&
358 intel->intelScreen->textureSize > 4*1024*1024);
359
360 switch ( internalFormat ) {
361 case 4:
362 case GL_RGBA:
363 case GL_COMPRESSED_RGBA:
364 if ( format == GL_BGRA ) {
365 if ( type == GL_UNSIGNED_INT_8_8_8_8_REV ) {
366 return &_mesa_texformat_argb8888;
367 }
368 else if ( type == GL_UNSIGNED_SHORT_4_4_4_4_REV ) {
369 return &_mesa_texformat_argb4444;
370 }
371 else if ( type == GL_UNSIGNED_SHORT_1_5_5_5_REV ) {
372 return &_mesa_texformat_argb1555;
373 }
374 }
375 return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb4444;
376
377 case 3:
378 case GL_RGB:
379 case GL_COMPRESSED_RGB:
380 if ( format == GL_RGB && type == GL_UNSIGNED_SHORT_5_6_5 ) {
381 return &_mesa_texformat_rgb565;
382 }
383 return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_rgb565;
384
385 case GL_RGBA8:
386 case GL_RGB10_A2:
387 case GL_RGBA12:
388 case GL_RGBA16:
389 return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb4444;
390
391 case GL_RGBA4:
392 case GL_RGBA2:
393 return &_mesa_texformat_argb4444;
394
395 case GL_RGB5_A1:
396 return &_mesa_texformat_argb1555;
397
398 case GL_RGB8:
399 case GL_RGB10:
400 case GL_RGB12:
401 case GL_RGB16:
402 return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_rgb565;
403
404 case GL_RGB5:
405 case GL_RGB4:
406 case GL_R3_G3_B2:
407 return &_mesa_texformat_rgb565;
408
409 case GL_ALPHA:
410 case GL_ALPHA4:
411 case GL_ALPHA8:
412 case GL_ALPHA12:
413 case GL_ALPHA16:
414 case GL_COMPRESSED_ALPHA:
415 /* if (1 || intel->intelScreen->deviceID == PCI_CHIP_I915_G) */
416 return &_mesa_texformat_a8;
417 /* else */
418 /* return &_mesa_texformat_al88; */
419
420 case 1:
421 case GL_LUMINANCE:
422 case GL_LUMINANCE4:
423 case GL_LUMINANCE8:
424 case GL_LUMINANCE12:
425 case GL_LUMINANCE16:
426 case GL_COMPRESSED_LUMINANCE:
427 return &_mesa_texformat_l8;
428
429 case 2:
430 case GL_LUMINANCE_ALPHA:
431 case GL_LUMINANCE4_ALPHA4:
432 case GL_LUMINANCE6_ALPHA2:
433 case GL_LUMINANCE8_ALPHA8:
434 case GL_LUMINANCE12_ALPHA4:
435 case GL_LUMINANCE12_ALPHA12:
436 case GL_LUMINANCE16_ALPHA16:
437 case GL_COMPRESSED_LUMINANCE_ALPHA:
438 return &_mesa_texformat_al88;
439
440 case GL_INTENSITY:
441 case GL_INTENSITY4:
442 case GL_INTENSITY8:
443 case GL_INTENSITY12:
444 case GL_INTENSITY16:
445 case GL_COMPRESSED_INTENSITY:
446 return &_mesa_texformat_i8;
447
448 case GL_YCBCR_MESA:
449 if (type == GL_UNSIGNED_SHORT_8_8_MESA ||
450 type == GL_UNSIGNED_BYTE)
451 return &_mesa_texformat_ycbcr;
452 else
453 return &_mesa_texformat_ycbcr_rev;
454
455 default:
456 fprintf(stderr, "unexpected texture format in %s\n", __FUNCTION__);
457 return NULL;
458 }
459
460 return NULL; /* never get here */
461 }
462
463
464
465 void intelDestroyTexObj(intelContextPtr intel, intelTextureObjectPtr t)
466 {
467 unsigned i;
468
469 if ( intel == NULL )
470 return;
471
472 if ( t->age > intel->dirtyAge )
473 intel->dirtyAge = t->age;
474
475 for ( i = 0 ; i < MAX_TEXTURE_UNITS ; i++ ) {
476 if ( t == intel->CurrentTexObj[ i ] )
477 intel->CurrentTexObj[ i ] = NULL;
478 }
479 }
480
481
482
483 /* Upload an image from mesa's internal copy. Image may be 1D, 2D or
484 * 3D. Cubemaps are expanded elsewhere.
485 */
486 static void intelUploadTexImage( intelContextPtr intel,
487 intelTextureObjectPtr t,
488 const struct gl_texture_image *image,
489 const GLuint offset )
490 {
491
492 if (!image || !image->Data)
493 return;
494
495 if (image->Depth == 1 && image->IsClientData) {
496 if (INTEL_DEBUG & DEBUG_TEXTURE)
497 fprintf(stderr, "Blit uploading\n");
498
499 /* Do it with a blit.
500 */
501 intelEmitCopyBlitLocked( intel,
502 image->TexFormat->TexelBytes,
503 image->RowStride, /* ? */
504 intelGetMemoryOffsetMESA( NULL, 0, image->Data ),
505 t->Pitch / image->TexFormat->TexelBytes,
506 intelGetMemoryOffsetMESA( NULL, 0, t->BufAddr + offset ),
507 0, 0,
508 0, 0,
509 image->Width,
510 image->Height);
511 }
512 else {
513 GLuint row_len = image->Width * image->TexFormat->TexelBytes;
514 GLubyte *dst = (GLubyte *)(t->BufAddr + offset);
515 GLubyte *src = (GLubyte *)image->Data;
516 GLuint d, j;
517
518 if (INTEL_DEBUG & DEBUG_TEXTURE)
519 fprintf(stderr,
520 "Upload image %dx%dx%d offset %xm row_len %x "
521 "pitch %x depth_pitch %x\n",
522 image->Width, image->Height, image->Depth, offset,
523 row_len, t->Pitch, t->depth_pitch);
524
525 if (row_len == t->Pitch) {
526 for (d = 0; d < image->Depth; d++) {
527 memcpy( dst, src, t->Pitch * image->Height );
528 dst += t->depth_pitch;
529 src += row_len * image->Height;
530 }
531 }
532 else {
533 for (d = 0 ; d < image->Depth ; d++) {
534 for (j = 0 ; j < image->Height ; j++) {
535 __memcpy(dst, src, row_len );
536 src += row_len;
537 dst += t->Pitch;
538 }
539
540 dst += t->depth_pitch - (t->Pitch * image->Height);
541 }
542 }
543 }
544 }
545
546
547
548 int intelUploadTexImages( intelContextPtr intel,
549 intelTextureObjectPtr t,
550 GLuint face)
551 {
552 const int numLevels = t->base.lastLevel - t->base.firstLevel + 1;
553 const struct gl_texture_image *firstImage = t->image[face][t->base.firstLevel].image;
554 int pitch = firstImage->RowStride * firstImage->TexFormat->TexelBytes;
555
556 /* Can we texture out of the existing client data? */
557 if ( numLevels == 1 &&
558 firstImage->IsClientData &&
559 (pitch & 3) == 0) {
560
561 if (INTEL_DEBUG & DEBUG_TEXTURE)
562 fprintf(stderr, "AGP texturing from client memory\n");
563
564 t->TextureOffset = intelAgpOffsetFromVirtual( intel, firstImage->Data );
565 t->BufAddr = 0;
566 t->dirty = ~0;
567 return GL_TRUE;
568 }
569 else {
570 if (INTEL_DEBUG & DEBUG_TEXTURE)
571 fprintf(stderr, "Uploading client data to agp\n");
572
573 INTEL_FIREVERTICES( intel );
574 LOCK_HARDWARE( intel );
575
576 if ( t->base.memBlock == NULL ) {
577 int heap;
578
579 heap = driAllocateTexture( intel->texture_heaps, intel->nr_heaps,
580 (driTextureObject *) t );
581 if ( heap == -1 ) {
582 UNLOCK_HARDWARE( intel );
583 return GL_FALSE;
584 }
585
586 /* Set the base offset of the texture image */
587 t->BufAddr = intel->intelScreen->tex.map + t->base.memBlock->ofs;
588 t->TextureOffset = intel->intelScreen->textureOffset + t->base.memBlock->ofs;
589 t->dirty = ~0;
590 }
591
592
593 /* Let the world know we've used this memory recently.
594 */
595 driUpdateTextureLRU( (driTextureObject *) t );
596
597
598 /* Upload any images that are new */
599 if (t->base.dirty_images[face]) {
600 int i;
601
602 intelWaitForIdle( intel );
603
604 for (i = 0 ; i < numLevels ; i++) {
605 int level = i + t->base.firstLevel;
606
607 if (t->base.dirty_images[face] & (1<<level)) {
608
609 const struct gl_texture_image *image = t->image[face][i].image;
610 GLuint offset = t->image[face][i].offset;
611
612 if (INTEL_DEBUG & DEBUG_TEXTURE)
613 fprintf(stderr, "upload level %d, offset %x\n",
614 level, offset);
615
616 intelUploadTexImage( intel, t, image, offset );
617 }
618 }
619 t->base.dirty_images[face] = 0;
620 intel->perf_boxes |= I830_BOX_TEXTURE_LOAD;
621 }
622
623 UNLOCK_HARDWARE( intel );
624 return GL_TRUE;
625 }
626 }
627
628 /**
629 * Allocate a new texture object.
630 * Called via ctx->Driver.NewTextureObject.
631 * Note: this function will be called during context creation to
632 * allocate the default texture objects.
633 * Note: we could use containment here to 'derive' the driver-specific
634 * texture object from the core mesa gl_texture_object. Not done at this time.
635 */
636 static struct gl_texture_object *
637 intelNewTextureObject( GLcontext *ctx, GLuint name, GLenum target )
638 {
639 struct gl_texture_object *obj = _mesa_new_texture_object(ctx, name, target);
640 INTEL_CONTEXT(ctx)->vtbl.alloc_tex_obj( obj );
641 return obj;
642 }
643
644
645 void intelInitTextureFuncs( struct dd_function_table *functions )
646 {
647 functions->NewTextureObject = intelNewTextureObject;
648 functions->ChooseTextureFormat = intelChooseTextureFormat;
649 functions->TexImage1D = intelTexImage1D;
650 functions->TexImage2D = intelTexImage2D;
651 functions->TexImage3D = intelTexImage3D;
652 functions->TexSubImage1D = intelTexSubImage1D;
653 functions->TexSubImage2D = intelTexSubImage2D;
654 functions->TexSubImage3D = intelTexSubImage3D;
655 functions->CopyTexImage1D = _swrast_copy_teximage1d;
656 functions->CopyTexImage2D = _swrast_copy_teximage2d;
657 functions->CopyTexSubImage1D = _swrast_copy_texsubimage1d;
658 functions->CopyTexSubImage2D = _swrast_copy_texsubimage2d;
659 functions->CopyTexSubImage3D = _swrast_copy_texsubimage3d;
660 functions->DeleteTexture = intelDeleteTexture;
661 functions->UpdateTexturePalette = NULL;
662 functions->IsTextureResident = driIsTextureResident;
663 functions->TestProxyTexImage = _mesa_test_proxy_teximage;
664 functions->DeleteTexture = intelDeleteTexture;
665 }