fix range reduction for sin/cos in i915tex (#11609)
[mesa.git] / src / mesa / drivers / dri / i915tex / intel_fbo.c
1 /**************************************************************************
2 *
3 * Copyright 2006 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
29 #include "imports.h"
30 #include "mtypes.h"
31 #include "fbobject.h"
32 #include "framebuffer.h"
33 #include "renderbuffer.h"
34 #include "context.h"
35 #include "texformat.h"
36 #include "texrender.h"
37
38 #include "intel_context.h"
39 #include "intel_buffers.h"
40 #include "intel_depthstencil.h"
41 #include "intel_fbo.h"
42 #include "intel_mipmap_tree.h"
43 #include "intel_regions.h"
44 #include "intel_span.h"
45
46
47 #define FILE_DEBUG_FLAG DEBUG_FBO
48
49 #define INTEL_RB_CLASS 0x12345678
50
51
52 /* XXX FBO: move this to intel_context.h (inlined) */
53 /**
54 * Return a gl_renderbuffer ptr casted to intel_renderbuffer.
55 * NULL will be returned if the rb isn't really an intel_renderbuffer.
56 * This is determiend by checking the ClassID.
57 */
58 struct intel_renderbuffer *
59 intel_renderbuffer(struct gl_renderbuffer *rb)
60 {
61 struct intel_renderbuffer *irb = (struct intel_renderbuffer *) rb;
62 if (irb && irb->Base.ClassID == INTEL_RB_CLASS) {
63 /*_mesa_warning(NULL, "Returning non-intel Rb\n");*/
64 return irb;
65 }
66 else
67 return NULL;
68 }
69
70
71 struct intel_renderbuffer *
72 intel_get_renderbuffer(struct gl_framebuffer *fb, GLuint attIndex)
73 {
74 return intel_renderbuffer(fb->Attachment[attIndex].Renderbuffer);
75 }
76
77
78 void
79 intel_flip_renderbuffers(struct intel_framebuffer *intel_fb)
80 {
81 int current_page = intel_fb->pf_current_page;
82 int next_page = (current_page + 1) % intel_fb->pf_num_pages;
83 struct gl_renderbuffer *tmp_rb;
84
85 /* Exchange renderbuffers if necessary but make sure their reference counts
86 * are preserved.
87 */
88 if (intel_fb->color_rb[current_page] &&
89 intel_fb->Base.Attachment[BUFFER_FRONT_LEFT].Renderbuffer !=
90 &intel_fb->color_rb[current_page]->Base) {
91 tmp_rb = NULL;
92 _mesa_reference_renderbuffer(&tmp_rb,
93 intel_fb->Base.Attachment[BUFFER_FRONT_LEFT].Renderbuffer);
94 tmp_rb = &intel_fb->color_rb[current_page]->Base;
95 _mesa_reference_renderbuffer(
96 &intel_fb->Base.Attachment[BUFFER_FRONT_LEFT].Renderbuffer, tmp_rb);
97 _mesa_reference_renderbuffer(&tmp_rb, NULL);
98 }
99
100 if (intel_fb->color_rb[next_page] &&
101 intel_fb->Base.Attachment[BUFFER_BACK_LEFT].Renderbuffer !=
102 &intel_fb->color_rb[next_page]->Base) {
103 tmp_rb = NULL;
104 _mesa_reference_renderbuffer(&tmp_rb,
105 intel_fb->Base.Attachment[BUFFER_BACK_LEFT].Renderbuffer);
106 tmp_rb = &intel_fb->color_rb[next_page]->Base;
107 _mesa_reference_renderbuffer(
108 &intel_fb->Base.Attachment[BUFFER_BACK_LEFT].Renderbuffer, tmp_rb);
109 _mesa_reference_renderbuffer(&tmp_rb, NULL);
110 }
111 }
112
113
114 struct intel_region *
115 intel_get_rb_region(struct gl_framebuffer *fb, GLuint attIndex)
116 {
117 struct intel_renderbuffer *irb = intel_get_renderbuffer(fb, attIndex);
118
119 if (irb)
120 return irb->region;
121 else
122 return NULL;
123 }
124
125
126
127 /**
128 * Create a new framebuffer object.
129 */
130 static struct gl_framebuffer *
131 intel_new_framebuffer(GLcontext * ctx, GLuint name)
132 {
133 /* Only drawable state in intel_framebuffer at this time, just use Mesa's
134 * class
135 */
136 return _mesa_new_framebuffer(ctx, name);
137 }
138
139
140 static void
141 intel_delete_renderbuffer(struct gl_renderbuffer *rb)
142 {
143 GET_CURRENT_CONTEXT(ctx);
144 struct intel_context *intel = intel_context(ctx);
145 struct intel_renderbuffer *irb = intel_renderbuffer(rb);
146
147 ASSERT(irb);
148
149 DBG("freeing renderbuffer\n");
150
151 if (irb->PairedStencil || irb->PairedDepth) {
152 intel_unpair_depth_stencil(ctx, irb);
153 }
154
155 if (intel && irb->region) {
156 intel_region_release(&irb->region);
157 }
158
159 _mesa_free(irb);
160 }
161
162
163
164 /**
165 * Return a pointer to a specific pixel in a renderbuffer.
166 */
167 static void *
168 intel_get_pointer(GLcontext * ctx, struct gl_renderbuffer *rb,
169 GLint x, GLint y)
170 {
171 /* By returning NULL we force all software rendering to go through
172 * the span routines.
173 */
174 return NULL;
175 }
176
177
178
179 /**
180 * Called via glRenderbufferStorageEXT() to set the format and allocate
181 * storage for a user-created (or priv buffer) renderbuffer.
182 */
183 static GLboolean
184 intel_alloc_renderbuffer_storage(GLcontext * ctx, struct gl_renderbuffer *rb,
185 GLenum internalFormat,
186 GLuint width, GLuint height)
187 {
188 struct intel_context *intel = intel_context(ctx);
189 struct intel_renderbuffer *irb = intel_renderbuffer(rb);
190 GLboolean softwareBuffer = GL_FALSE;
191 int cpp;
192
193 switch (internalFormat) {
194 case GL_R3_G3_B2:
195 case GL_RGB4:
196 case GL_RGB5:
197 rb->_ActualFormat = GL_RGB5;
198 rb->DataType = GL_UNSIGNED_BYTE;
199 rb->RedBits = 5;
200 rb->GreenBits = 6;
201 rb->BlueBits = 5;
202 cpp = 2;
203 break;
204 case GL_RGB:
205 case GL_RGB8:
206 case GL_RGB10:
207 case GL_RGB12:
208 case GL_RGB16:
209 case GL_RGBA:
210 case GL_RGBA2:
211 case GL_RGBA4:
212 case GL_RGB5_A1:
213 case GL_RGBA8:
214 case GL_RGB10_A2:
215 case GL_RGBA12:
216 case GL_RGBA16:
217 rb->_ActualFormat = GL_RGBA8;
218 rb->DataType = GL_UNSIGNED_BYTE;
219 rb->RedBits = 8;
220 rb->GreenBits = 8;
221 rb->BlueBits = 8;
222 rb->AlphaBits = 8;
223 cpp = 4;
224 break;
225 case GL_STENCIL_INDEX:
226 case GL_STENCIL_INDEX1_EXT:
227 case GL_STENCIL_INDEX4_EXT:
228 case GL_STENCIL_INDEX8_EXT:
229 case GL_STENCIL_INDEX16_EXT:
230 /* alloc a depth+stencil buffer */
231 rb->_ActualFormat = GL_DEPTH24_STENCIL8_EXT;
232 rb->DataType = GL_UNSIGNED_INT_24_8_EXT;
233 rb->StencilBits = 8;
234 cpp = 4;
235 break;
236 case GL_DEPTH_COMPONENT16:
237 rb->_ActualFormat = GL_DEPTH_COMPONENT16;
238 rb->DataType = GL_UNSIGNED_SHORT;
239 rb->DepthBits = 16;
240 cpp = 2;
241 break;
242 case GL_DEPTH_COMPONENT:
243 case GL_DEPTH_COMPONENT24:
244 case GL_DEPTH_COMPONENT32:
245 rb->_ActualFormat = GL_DEPTH24_STENCIL8_EXT;
246 rb->DataType = GL_UNSIGNED_INT_24_8_EXT;
247 rb->DepthBits = 24;
248 cpp = 4;
249 break;
250 case GL_DEPTH_STENCIL_EXT:
251 case GL_DEPTH24_STENCIL8_EXT:
252 rb->_ActualFormat = GL_DEPTH24_STENCIL8_EXT;
253 rb->DataType = GL_UNSIGNED_INT_24_8_EXT;
254 rb->DepthBits = 24;
255 rb->StencilBits = 8;
256 cpp = 4;
257 break;
258 default:
259 _mesa_problem(ctx,
260 "Unexpected format (%x) in intel_alloc_renderbuffer_storage", internalFormat);
261 return GL_FALSE;
262 }
263
264 intelFlush(ctx);
265
266 /* free old region */
267 if (irb->region) {
268 intel_region_release(&irb->region);
269 }
270
271 /* allocate new memory region/renderbuffer */
272 if (softwareBuffer) {
273 return _mesa_soft_renderbuffer_storage(ctx, rb, internalFormat,
274 width, height);
275 }
276 else {
277 /* Choose a pitch to match hardware requirements:
278 */
279 GLuint pitch = ((cpp * width + 63) & ~63) / cpp;
280
281 /* alloc hardware renderbuffer */
282 DBG("Allocating %d x %d Intel RBO (pitch %d)\n", width,
283 height, pitch);
284
285 irb->region = intel_region_alloc(intel->intelScreen, cpp, pitch, height);
286 if (!irb->region)
287 return GL_FALSE; /* out of memory? */
288
289 ASSERT(irb->region->buffer);
290
291 rb->Width = width;
292 rb->Height = height;
293
294 /* This sets the Get/PutRow/Value functions */
295 intel_set_span_functions(&irb->Base);
296
297 return GL_TRUE;
298 }
299 }
300
301
302 static void
303 intel_resize_buffers(GLcontext *ctx, struct gl_framebuffer *fb,
304 GLuint width, GLuint height)
305 {
306 struct intel_framebuffer *intel_fb = (struct intel_framebuffer*)fb;
307 int i;
308
309 _mesa_resize_framebuffer(ctx, fb, width, height);
310
311 fb->Initialized = GL_TRUE; /* XXX remove someday */
312
313 if (fb->Name != 0) {
314 return;
315 }
316
317 /* Make sure all window system renderbuffers are up to date */
318 for (i = 0; i < 3; i++) {
319 struct gl_renderbuffer *rb = &intel_fb->color_rb[i]->Base;
320
321 /* only resize if size is changing */
322 if (rb && (rb->Width != width || rb->Height != height)) {
323 rb->AllocStorage(ctx, rb, rb->InternalFormat, width, height);
324 }
325 }
326 }
327
328 static GLboolean
329 intel_nop_alloc_storage(GLcontext * ctx, struct gl_renderbuffer *rb,
330 GLenum internalFormat, GLuint width, GLuint height)
331 {
332 _mesa_problem(ctx, "intel_op_alloc_storage should never be called.");
333 return GL_FALSE;
334 }
335
336
337
338 struct intel_renderbuffer *
339 intel_new_renderbuffer_fb(GLuint intFormat)
340 {
341 struct intel_renderbuffer *irb;
342
343 irb = CALLOC_STRUCT(intel_renderbuffer);
344 if (!irb) {
345 _mesa_error(NULL, GL_OUT_OF_MEMORY, "creating renderbuffer");
346 return NULL;
347 }
348
349 _mesa_init_renderbuffer(&irb->Base, 0);
350 irb->Base.ClassID = INTEL_RB_CLASS;
351 irb->Base.InternalFormat = intFormat;
352
353 switch (intFormat) {
354 case GL_RGB5:
355 case GL_RGBA8:
356 irb->Base._BaseFormat = GL_RGBA;
357 break;
358 case GL_DEPTH_COMPONENT16:
359 irb->Base._BaseFormat = GL_DEPTH_COMPONENT;
360 break;
361 case GL_DEPTH24_STENCIL8_EXT:
362 irb->Base._BaseFormat = GL_DEPTH_STENCIL_EXT;
363 break;
364 default:
365 assert(0);
366 }
367
368 /* intel-specific methods */
369 irb->Base.Delete = intel_delete_renderbuffer;
370 irb->Base.AllocStorage = intel_alloc_renderbuffer_storage;
371 irb->Base.GetPointer = intel_get_pointer;
372 /* span routines set in alloc_storage function */
373
374 return irb;
375 }
376
377 /**
378 * Create a new renderbuffer object.
379 * Typically called via glBindRenderbufferEXT().
380 */
381 static struct gl_renderbuffer *
382 intel_new_renderbuffer(GLcontext * ctx, GLuint name)
383 {
384 /*struct intel_context *intel = intel_context(ctx); */
385 struct intel_renderbuffer *irb;
386
387 irb = CALLOC_STRUCT(intel_renderbuffer);
388 if (!irb) {
389 _mesa_error(ctx, GL_OUT_OF_MEMORY, "creating renderbuffer");
390 return NULL;
391 }
392
393 _mesa_init_renderbuffer(&irb->Base, name);
394 irb->Base.ClassID = INTEL_RB_CLASS;
395
396 /* intel-specific methods */
397 irb->Base.Delete = intel_delete_renderbuffer;
398 irb->Base.AllocStorage = intel_alloc_renderbuffer_storage;
399 irb->Base.GetPointer = intel_get_pointer;
400 /* span routines set in alloc_storage function */
401
402 return &irb->Base;
403 }
404
405
406 /**
407 * Called via glBindFramebufferEXT().
408 */
409 static void
410 intel_bind_framebuffer(GLcontext * ctx, GLenum target,
411 struct gl_framebuffer *fb, struct gl_framebuffer *fbread)
412 {
413 if (target == GL_FRAMEBUFFER_EXT || target == GL_DRAW_FRAMEBUFFER_EXT) {
414 intel_draw_buffer(ctx, fb);
415 /* Integer depth range depends on depth buffer bits */
416 ctx->Driver.DepthRange(ctx, ctx->Viewport.Near, ctx->Viewport.Far);
417 }
418 else {
419 /* don't need to do anything if target == GL_READ_FRAMEBUFFER_EXT */
420 }
421 }
422
423
424 /**
425 * Called via glFramebufferRenderbufferEXT().
426 */
427 static void
428 intel_framebuffer_renderbuffer(GLcontext * ctx,
429 struct gl_framebuffer *fb,
430 GLenum attachment, struct gl_renderbuffer *rb)
431 {
432 DBG("Intel FramebufferRenderbuffer %u %u\n", fb->Name, rb ? rb->Name : 0);
433
434 intelFlush(ctx);
435
436 _mesa_framebuffer_renderbuffer(ctx, fb, attachment, rb);
437 intel_draw_buffer(ctx, fb);
438 }
439
440
441 /**
442 * When glFramebufferTexture[123]D is called this function sets up the
443 * gl_renderbuffer wrapper around the texture image.
444 * This will have the region info needed for hardware rendering.
445 */
446 static struct intel_renderbuffer *
447 intel_wrap_texture(GLcontext * ctx, struct gl_texture_image *texImage)
448 {
449 const GLuint name = ~0; /* not significant, but distinct for debugging */
450 struct intel_renderbuffer *irb;
451
452 /* make an intel_renderbuffer to wrap the texture image */
453 irb = CALLOC_STRUCT(intel_renderbuffer);
454 if (!irb) {
455 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glFramebufferTexture");
456 return NULL;
457 }
458
459 _mesa_init_renderbuffer(&irb->Base, name);
460 irb->Base.ClassID = INTEL_RB_CLASS;
461
462 if (texImage->TexFormat == &_mesa_texformat_argb8888) {
463 irb->Base._ActualFormat = GL_RGBA8;
464 irb->Base._BaseFormat = GL_RGBA;
465 DBG("Render to RGBA8 texture OK\n");
466 }
467 else if (texImage->TexFormat == &_mesa_texformat_rgb565) {
468 irb->Base._ActualFormat = GL_RGB5;
469 irb->Base._BaseFormat = GL_RGB;
470 DBG("Render to RGB5 texture OK\n");
471 }
472 else if (texImage->TexFormat == &_mesa_texformat_z16) {
473 irb->Base._ActualFormat = GL_DEPTH_COMPONENT16;
474 irb->Base._BaseFormat = GL_DEPTH_COMPONENT;
475 DBG("Render to DEPTH16 texture OK\n");
476 }
477 else {
478 DBG("Render to texture BAD FORMAT %d\n",
479 texImage->TexFormat->MesaFormat);
480 _mesa_free(irb);
481 return NULL;
482 }
483
484 irb->Base.InternalFormat = irb->Base._ActualFormat;
485 irb->Base.Width = texImage->Width;
486 irb->Base.Height = texImage->Height;
487 irb->Base.DataType = GL_UNSIGNED_BYTE; /* FBO XXX fix */
488 irb->Base.RedBits = texImage->TexFormat->RedBits;
489 irb->Base.GreenBits = texImage->TexFormat->GreenBits;
490 irb->Base.BlueBits = texImage->TexFormat->BlueBits;
491 irb->Base.AlphaBits = texImage->TexFormat->AlphaBits;
492 irb->Base.DepthBits = texImage->TexFormat->DepthBits;
493
494 irb->Base.Delete = intel_delete_renderbuffer;
495 irb->Base.AllocStorage = intel_nop_alloc_storage;
496 intel_set_span_functions(&irb->Base);
497
498 irb->RenderToTexture = GL_TRUE;
499
500 return irb;
501 }
502
503
504 /**
505 * Called by glFramebufferTexture[123]DEXT() (and other places) to
506 * prepare for rendering into texture memory. This might be called
507 * many times to choose different texture levels, cube faces, etc
508 * before intel_finish_render_texture() is ever called.
509 */
510 static void
511 intel_render_texture(GLcontext * ctx,
512 struct gl_framebuffer *fb,
513 struct gl_renderbuffer_attachment *att)
514 {
515 struct gl_texture_image *newImage
516 = att->Texture->Image[att->CubeMapFace][att->TextureLevel];
517 struct intel_renderbuffer *irb = intel_renderbuffer(att->Renderbuffer);
518 struct intel_texture_image *intel_image;
519 GLuint imageOffset;
520
521 (void) fb;
522
523 ASSERT(newImage);
524
525 if (!irb) {
526 irb = intel_wrap_texture(ctx, newImage);
527 if (irb) {
528 /* bind the wrapper to the attachment point */
529 _mesa_reference_renderbuffer(&att->Renderbuffer, &irb->Base);
530 }
531 else {
532 /* fallback to software rendering */
533 _mesa_render_texture(ctx, fb, att);
534 return;
535 }
536 }
537
538 DBG("Begin render texture tid %x tex=%u w=%d h=%d refcount=%d\n",
539 _glthread_GetID(),
540 att->Texture->Name, newImage->Width, newImage->Height,
541 irb->Base.RefCount);
542
543 /* point the renderbufer's region to the texture image region */
544 intel_image = intel_texture_image(newImage);
545 if (irb->region != intel_image->mt->region) {
546 if (irb->region)
547 intel_region_release(&irb->region);
548 intel_region_reference(&irb->region, intel_image->mt->region);
549 }
550
551 /* compute offset of the particular 2D image within the texture region */
552 imageOffset = intel_miptree_image_offset(intel_image->mt,
553 att->CubeMapFace,
554 att->TextureLevel);
555
556 if (att->Texture->Target == GL_TEXTURE_3D) {
557 const GLuint *offsets = intel_miptree_depth_offsets(intel_image->mt,
558 att->TextureLevel);
559 imageOffset += offsets[att->Zoffset];
560 }
561
562 /* store that offset in the region */
563 intel_image->mt->region->draw_offset = imageOffset;
564
565 /* update drawing region, etc */
566 intel_draw_buffer(ctx, fb);
567 }
568
569
570 /**
571 * Called by Mesa when rendering to a texture is done.
572 */
573 static void
574 intel_finish_render_texture(GLcontext * ctx,
575 struct gl_renderbuffer_attachment *att)
576 {
577 struct intel_renderbuffer *irb = intel_renderbuffer(att->Renderbuffer);
578
579 DBG("End render texture (tid %x) tex %u\n", _glthread_GetID(), att->Texture->Name);
580
581 if (irb) {
582 /* just release the region */
583 intel_region_release(&irb->region);
584 }
585 else if (att->Renderbuffer) {
586 /* software fallback */
587 _mesa_finish_render_texture(ctx, att);
588 /* XXX FBO: Need to unmap the buffer (or in intelSpanRenderStart???) */
589 }
590 }
591
592
593 /**
594 * Do one-time context initializations related to GL_EXT_framebuffer_object.
595 * Hook in device driver functions.
596 */
597 void
598 intel_fbo_init(struct intel_context *intel)
599 {
600 intel->ctx.Driver.NewFramebuffer = intel_new_framebuffer;
601 intel->ctx.Driver.NewRenderbuffer = intel_new_renderbuffer;
602 intel->ctx.Driver.BindFramebuffer = intel_bind_framebuffer;
603 intel->ctx.Driver.FramebufferRenderbuffer = intel_framebuffer_renderbuffer;
604 intel->ctx.Driver.RenderTexture = intel_render_texture;
605 intel->ctx.Driver.FinishRenderTexture = intel_finish_render_texture;
606 intel->ctx.Driver.ResizeBuffers = intel_resize_buffers;
607 }