radeon_fbo.c revision 77e6fb17d96ed9d9b3c2f52999e93da12a466405
1/**************************************************************************
2 *
3 * Copyright 2008 Red Hat Inc.
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 "main/imports.h"
30#include "main/macros.h"
31#include "main/mtypes.h"
32#include "main/enums.h"
33#include "main/fbobject.h"
34#include "main/framebuffer.h"
35#include "main/renderbuffer.h"
36#include "main/context.h"
37#include "main/texrender.h"
38#include "drivers/common/meta.h"
39
40#include "radeon_common.h"
41#include "radeon_mipmap_tree.h"
42
43#define FILE_DEBUG_FLAG RADEON_TEXTURE
44#define DBG(...) do {                                           \
45        if (RADEON_DEBUG & FILE_DEBUG_FLAG)                      \
46                _mesa_printf(__VA_ARGS__);                      \
47} while(0)
48
49static struct gl_framebuffer *
50radeon_new_framebuffer(GLcontext *ctx, GLuint name)
51{
52  return _mesa_new_framebuffer(ctx, name);
53}
54
55static void
56radeon_delete_renderbuffer(struct gl_renderbuffer *rb)
57{
58  struct radeon_renderbuffer *rrb = radeon_renderbuffer(rb);
59
60  radeon_print(RADEON_TEXTURE, RADEON_TRACE,
61		"%s(rb %p, rrb %p) \n",
62		__func__, rb, rrb);
63
64  ASSERT(rrb);
65
66  if (rrb && rrb->bo) {
67    radeon_bo_unref(rrb->bo);
68  }
69  _mesa_free(rrb);
70}
71
72static void *
73radeon_get_pointer(GLcontext *ctx, struct gl_renderbuffer *rb,
74		   GLint x, GLint y)
75{
76  radeon_print(RADEON_TEXTURE, RADEON_TRACE,
77		"%s(%p, rb %p) \n",
78		__func__, ctx, rb);
79
80  return NULL;
81}
82
83/**
84 * Called via glRenderbufferStorageEXT() to set the format and allocate
85 * storage for a user-created renderbuffer.
86 */
87static GLboolean
88radeon_alloc_renderbuffer_storage(GLcontext * ctx, struct gl_renderbuffer *rb,
89                                 GLenum internalFormat,
90                                 GLuint width, GLuint height)
91{
92  struct radeon_context *radeon = RADEON_CONTEXT(ctx);
93  struct radeon_renderbuffer *rrb = radeon_renderbuffer(rb);
94  GLboolean software_buffer = GL_FALSE;
95  int cpp;
96
97  radeon_print(RADEON_TEXTURE, RADEON_TRACE,
98		"%s(%p, rb %p) \n",
99		__func__, ctx, rb);
100
101   ASSERT(rb->Name != 0);
102  switch (internalFormat) {
103   case GL_R3_G3_B2:
104   case GL_RGB4:
105   case GL_RGB5:
106      rb->Format = _dri_texformat_rgb565;
107      rb->DataType = GL_UNSIGNED_BYTE;
108      cpp = 2;
109      break;
110   case GL_RGB:
111   case GL_RGB8:
112   case GL_RGB10:
113   case GL_RGB12:
114   case GL_RGB16:
115      rb->Format = _dri_texformat_argb8888;
116      rb->DataType = GL_UNSIGNED_BYTE;
117      cpp = 4;
118      break;
119   case GL_RGBA:
120   case GL_RGBA2:
121   case GL_RGBA4:
122   case GL_RGB5_A1:
123   case GL_RGBA8:
124   case GL_RGB10_A2:
125   case GL_RGBA12:
126   case GL_RGBA16:
127      rb->Format = _dri_texformat_argb8888;
128      rb->DataType = GL_UNSIGNED_BYTE;
129      cpp = 4;
130      break;
131   case GL_STENCIL_INDEX:
132   case GL_STENCIL_INDEX1_EXT:
133   case GL_STENCIL_INDEX4_EXT:
134   case GL_STENCIL_INDEX8_EXT:
135   case GL_STENCIL_INDEX16_EXT:
136      /* alloc a depth+stencil buffer */
137      rb->Format = MESA_FORMAT_S8_Z24;
138      rb->DataType = GL_UNSIGNED_INT_24_8_EXT;
139      cpp = 4;
140      break;
141   case GL_DEPTH_COMPONENT16:
142      rb->Format = MESA_FORMAT_Z16;
143      rb->DataType = GL_UNSIGNED_SHORT;
144      cpp = 2;
145      break;
146   case GL_DEPTH_COMPONENT:
147   case GL_DEPTH_COMPONENT24:
148   case GL_DEPTH_COMPONENT32:
149      rb->Format = MESA_FORMAT_X8_Z24;
150      rb->DataType = GL_UNSIGNED_INT;
151      cpp = 4;
152      break;
153   case GL_DEPTH_STENCIL_EXT:
154   case GL_DEPTH24_STENCIL8_EXT:
155      rb->Format = MESA_FORMAT_S8_Z24;
156      rb->DataType = GL_UNSIGNED_INT_24_8_EXT;
157      cpp = 4;
158      break;
159   default:
160      _mesa_problem(ctx,
161                    "Unexpected format in radeon_alloc_renderbuffer_storage");
162      return GL_FALSE;
163   }
164
165  rb->_BaseFormat = _mesa_base_fbo_format(ctx, internalFormat);
166
167  if (ctx->Driver.Flush)
168	  ctx->Driver.Flush(ctx); /* +r6/r7 */
169
170  if (rrb->bo)
171    radeon_bo_unref(rrb->bo);
172
173
174   if (software_buffer) {
175      return _mesa_soft_renderbuffer_storage(ctx, rb, internalFormat,
176                                             width, height);
177   }
178   else {
179     uint32_t size;
180     uint32_t pitch = ((cpp * width + 63) & ~63) / cpp;
181
182     if (RADEON_DEBUG & RADEON_MEMORY)
183	     fprintf(stderr,"Allocating %d x %d radeon RBO (pitch %d)\n", width,
184		     height, pitch);
185
186     size = pitch * height * cpp;
187     rrb->pitch = pitch * cpp;
188     rrb->cpp = cpp;
189     rrb->bo = radeon_bo_open(radeon->radeonScreen->bom,
190			      0,
191			      size,
192			      0,
193			      RADEON_GEM_DOMAIN_VRAM,
194			      0);
195     rb->Width = width;
196     rb->Height = height;
197       return GL_TRUE;
198   }
199
200}
201
202
203/**
204 * Called for each hardware renderbuffer when a _window_ is resized.
205 * Just update fields.
206 * Not used for user-created renderbuffers!
207 */
208static GLboolean
209radeon_alloc_window_storage(GLcontext * ctx, struct gl_renderbuffer *rb,
210                           GLenum internalFormat, GLuint width, GLuint height)
211{
212   ASSERT(rb->Name == 0);
213   rb->Width = width;
214   rb->Height = height;
215   rb->InternalFormat = internalFormat;
216  radeon_print(RADEON_TEXTURE, RADEON_TRACE,
217		"%s(%p, rb %p) \n",
218		__func__, ctx, rb);
219
220
221   return GL_TRUE;
222}
223
224
225static void
226radeon_resize_buffers(GLcontext *ctx, struct gl_framebuffer *fb,
227		     GLuint width, GLuint height)
228{
229     struct radeon_framebuffer *radeon_fb = (struct radeon_framebuffer*)fb;
230   int i;
231
232  radeon_print(RADEON_TEXTURE, RADEON_TRACE,
233		"%s(%p, fb %p) \n",
234		__func__, ctx, fb);
235
236   _mesa_resize_framebuffer(ctx, fb, width, height);
237
238   fb->Initialized = GL_TRUE; /* XXX remove someday */
239
240   if (fb->Name != 0) {
241      return;
242   }
243
244   /* Make sure all window system renderbuffers are up to date */
245   for (i = 0; i < 2; i++) {
246      struct gl_renderbuffer *rb = &radeon_fb->color_rb[i]->base;
247
248      /* only resize if size is changing */
249      if (rb && (rb->Width != width || rb->Height != height)) {
250	 rb->AllocStorage(ctx, rb, rb->InternalFormat, width, height);
251      }
252   }
253}
254
255
256/** Dummy function for gl_renderbuffer::AllocStorage() */
257static GLboolean
258radeon_nop_alloc_storage(GLcontext * ctx, struct gl_renderbuffer *rb,
259			 GLenum internalFormat, GLuint width, GLuint height)
260{
261   _mesa_problem(ctx, "radeon_op_alloc_storage should never be called.");
262   return GL_FALSE;
263}
264
265
266/**
267 * Create a renderbuffer for a window's color, depth and/or stencil buffer.
268 * Not used for user-created renderbuffers.
269 */
270struct radeon_renderbuffer *
271radeon_create_renderbuffer(gl_format format, __DRIdrawable *driDrawPriv)
272{
273    struct radeon_renderbuffer *rrb;
274
275    rrb = CALLOC_STRUCT(radeon_renderbuffer);
276
277    radeon_print(RADEON_TEXTURE, RADEON_TRACE,
278		"%s( rrb %p ) \n",
279		__func__, rrb);
280
281    if (!rrb)
282	return NULL;
283
284    _mesa_init_renderbuffer(&rrb->base, 0);
285    rrb->base.ClassID = RADEON_RB_CLASS;
286
287    rrb->base.Format = format;
288
289    switch (format) {
290        case MESA_FORMAT_RGB565:
291	    assert(_mesa_little_endian());
292	    rrb->base.DataType = GL_UNSIGNED_BYTE;
293            rrb->base._BaseFormat = GL_RGB;
294	    break;
295        case MESA_FORMAT_RGB565_REV:
296	    assert(!_mesa_little_endian());
297	    rrb->base.DataType = GL_UNSIGNED_BYTE;
298            rrb->base._BaseFormat = GL_RGB;
299	    break;
300        case MESA_FORMAT_XRGB8888:
301	    assert(_mesa_little_endian());
302	    rrb->base.DataType = GL_UNSIGNED_BYTE;
303            rrb->base._BaseFormat = GL_RGB;
304	    break;
305        case MESA_FORMAT_XRGB8888_REV:
306	    assert(!_mesa_little_endian());
307	    rrb->base.DataType = GL_UNSIGNED_BYTE;
308            rrb->base._BaseFormat = GL_RGB;
309	    break;
310	case MESA_FORMAT_ARGB8888:
311	    assert(_mesa_little_endian());
312	    rrb->base.DataType = GL_UNSIGNED_BYTE;
313            rrb->base._BaseFormat = GL_RGBA;
314	    break;
315	case MESA_FORMAT_ARGB8888_REV:
316	    assert(!_mesa_little_endian());
317	    rrb->base.DataType = GL_UNSIGNED_BYTE;
318            rrb->base._BaseFormat = GL_RGBA;
319	    break;
320	case MESA_FORMAT_S8:
321	    rrb->base.DataType = GL_UNSIGNED_BYTE;
322            rrb->base._BaseFormat = GL_STENCIL_INDEX;
323	    break;
324	case MESA_FORMAT_Z16:
325	    rrb->base.DataType = GL_UNSIGNED_SHORT;
326            rrb->base._BaseFormat = GL_DEPTH_COMPONENT;
327	    break;
328	case MESA_FORMAT_X8_Z24:
329	    rrb->base.DataType = GL_UNSIGNED_INT;
330            rrb->base._BaseFormat = GL_DEPTH_COMPONENT;
331	    break;
332	case MESA_FORMAT_S8_Z24:
333	    rrb->base.DataType = GL_UNSIGNED_INT_24_8_EXT;
334            rrb->base._BaseFormat = GL_DEPTH_STENCIL;
335	    break;
336	default:
337	    fprintf(stderr, "%s: Unknown format %s\n",
338                    __FUNCTION__, _mesa_get_format_name(format));
339	    _mesa_delete_renderbuffer(&rrb->base);
340	    return NULL;
341    }
342
343    rrb->dPriv = driDrawPriv;
344    rrb->base.InternalFormat = _mesa_get_format_base_format(format);
345
346    rrb->base.Delete = radeon_delete_renderbuffer;
347    rrb->base.AllocStorage = radeon_alloc_window_storage;
348    rrb->base.GetPointer = radeon_get_pointer;
349
350    rrb->bo = NULL;
351    return rrb;
352}
353
354static struct gl_renderbuffer *
355radeon_new_renderbuffer(GLcontext * ctx, GLuint name)
356{
357  struct radeon_renderbuffer *rrb;
358
359  rrb = CALLOC_STRUCT(radeon_renderbuffer);
360
361  radeon_print(RADEON_TEXTURE, RADEON_TRACE,
362		"%s(%p, rrb %p) \n",
363		__func__, ctx, rrb);
364
365  if (!rrb)
366    return NULL;
367
368  _mesa_init_renderbuffer(&rrb->base, name);
369  rrb->base.ClassID = RADEON_RB_CLASS;
370
371  rrb->base.Delete = radeon_delete_renderbuffer;
372  rrb->base.AllocStorage = radeon_alloc_renderbuffer_storage;
373  rrb->base.GetPointer = radeon_get_pointer;
374
375  return &rrb->base;
376}
377
378static void
379radeon_bind_framebuffer(GLcontext * ctx, GLenum target,
380                       struct gl_framebuffer *fb, struct gl_framebuffer *fbread)
381{
382  radeon_print(RADEON_TEXTURE, RADEON_TRACE,
383		"%s(%p, fb %p, target %s) \n",
384		__func__, ctx, fb,
385		_mesa_lookup_enum_by_nr(target));
386
387   if (target == GL_FRAMEBUFFER_EXT || target == GL_DRAW_FRAMEBUFFER_EXT) {
388      radeon_draw_buffer(ctx, fb);
389   }
390   else {
391      /* don't need to do anything if target == GL_READ_FRAMEBUFFER_EXT */
392   }
393}
394
395static void
396radeon_framebuffer_renderbuffer(GLcontext * ctx,
397                               struct gl_framebuffer *fb,
398                               GLenum attachment, struct gl_renderbuffer *rb)
399{
400
401	if (ctx->Driver.Flush)
402		ctx->Driver.Flush(ctx); /* +r6/r7 */
403
404	radeon_print(RADEON_TEXTURE, RADEON_TRACE,
405		"%s(%p, fb %p, rb %p) \n",
406		__func__, ctx, fb, rb);
407
408   _mesa_framebuffer_renderbuffer(ctx, fb, attachment, rb);
409   radeon_draw_buffer(ctx, fb);
410}
411
412
413/* TODO: According to EXT_fbo spec internal format of texture image
414 * once set during glTexImage call, should be preserved when
415 * attaching image to renderbuffer. When HW doesn't support
416 * rendering to format of attached image, set framebuffer
417 * completeness accordingly in radeon_validate_framebuffer (issue #79).
418 */
419static GLboolean
420radeon_update_wrapper(GLcontext *ctx, struct radeon_renderbuffer *rrb,
421		     struct gl_texture_image *texImage)
422{
423	int retry = 0;
424	gl_format texFormat;
425
426	radeon_print(RADEON_TEXTURE, RADEON_TRACE,
427		"%s(%p, rrb %p, texImage %p) \n",
428		__func__, ctx, rrb, texImage);
429
430restart:
431	if (texImage->TexFormat == _dri_texformat_argb8888) {
432		rrb->base.DataType = GL_UNSIGNED_BYTE;
433		DBG("Render to RGBA8 texture OK\n");
434	}
435	else if (texImage->TexFormat == _dri_texformat_rgb565) {
436		rrb->base.DataType = GL_UNSIGNED_BYTE;
437		DBG("Render to RGB5 texture OK\n");
438	}
439	else if (texImage->TexFormat == _dri_texformat_argb1555) {
440		rrb->base.DataType = GL_UNSIGNED_BYTE;
441		DBG("Render to ARGB1555 texture OK\n");
442	}
443	else if (texImage->TexFormat == _dri_texformat_argb4444) {
444		rrb->base.DataType = GL_UNSIGNED_BYTE;
445		DBG("Render to ARGB4444 texture OK\n");
446	}
447	else if (texImage->TexFormat == MESA_FORMAT_Z16) {
448		rrb->base.DataType = GL_UNSIGNED_SHORT;
449		DBG("Render to DEPTH16 texture OK\n");
450	}
451	else if (texImage->TexFormat == MESA_FORMAT_S8_Z24) {
452		rrb->base.DataType = GL_UNSIGNED_INT_24_8_EXT;
453		DBG("Render to DEPTH_STENCIL texture OK\n");
454	}
455	else {
456		/* try redoing the FBO */
457		if (retry == 1) {
458			DBG("Render to texture BAD FORMAT %d\n",
459			    texImage->TexFormat);
460			return GL_FALSE;
461		}
462                /* XXX why is the tex format being set here?
463                 * I think this can be removed.
464                 */
465		texImage->TexFormat = radeonChooseTextureFormat(ctx, texImage->InternalFormat, 0,
466								_mesa_get_format_datatype(texImage->TexFormat),
467								1);
468
469		retry++;
470		goto restart;
471	}
472
473	texFormat = texImage->TexFormat;
474
475	rrb->base.Format = texFormat;
476
477        rrb->cpp = _mesa_get_format_bytes(texFormat);
478	rrb->pitch = texImage->Width * rrb->cpp;
479	rrb->base.InternalFormat = texImage->InternalFormat;
480        rrb->base._BaseFormat = _mesa_base_fbo_format(ctx, rrb->base.InternalFormat);
481
482	rrb->base.Width = texImage->Width;
483	rrb->base.Height = texImage->Height;
484
485	rrb->base.Delete = radeon_delete_renderbuffer;
486	rrb->base.AllocStorage = radeon_nop_alloc_storage;
487
488	return GL_TRUE;
489}
490
491
492static struct radeon_renderbuffer *
493radeon_wrap_texture(GLcontext * ctx, struct gl_texture_image *texImage)
494{
495  const GLuint name = ~0;   /* not significant, but distinct for debugging */
496  struct radeon_renderbuffer *rrb;
497
498   /* make an radeon_renderbuffer to wrap the texture image */
499   rrb = CALLOC_STRUCT(radeon_renderbuffer);
500
501   radeon_print(RADEON_TEXTURE, RADEON_TRACE,
502		"%s(%p, rrb %p, texImage %p) \n",
503		__func__, ctx, rrb, texImage);
504
505   if (!rrb) {
506      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glFramebufferTexture");
507      return NULL;
508   }
509
510   _mesa_init_renderbuffer(&rrb->base, name);
511   rrb->base.ClassID = RADEON_RB_CLASS;
512
513   if (!radeon_update_wrapper(ctx, rrb, texImage)) {
514      _mesa_free(rrb);
515      return NULL;
516   }
517
518   return rrb;
519
520}
521static void
522radeon_render_texture(GLcontext * ctx,
523                     struct gl_framebuffer *fb,
524                     struct gl_renderbuffer_attachment *att)
525{
526   struct gl_texture_image *newImage
527      = att->Texture->Image[att->CubeMapFace][att->TextureLevel];
528   struct radeon_renderbuffer *rrb = radeon_renderbuffer(att->Renderbuffer);
529   radeon_texture_image *radeon_image;
530   GLuint imageOffset;
531
532  radeon_print(RADEON_TEXTURE, RADEON_TRACE,
533		"%s(%p, fb %p, rrb %p, att %p)\n",
534		__func__, ctx, fb, rrb, att);
535
536   (void) fb;
537
538   ASSERT(newImage);
539
540   if (newImage->Border != 0) {
541      /* Fallback on drawing to a texture with a border, which won't have a
542       * miptree.
543       */
544      _mesa_reference_renderbuffer(&att->Renderbuffer, NULL);
545      _mesa_render_texture(ctx, fb, att);
546      return;
547   }
548   else if (!rrb) {
549      rrb = radeon_wrap_texture(ctx, newImage);
550      if (rrb) {
551         /* bind the wrapper to the attachment point */
552         _mesa_reference_renderbuffer(&att->Renderbuffer, &rrb->base);
553      }
554      else {
555         /* fallback to software rendering */
556         _mesa_render_texture(ctx, fb, att);
557         return;
558      }
559   }
560
561   if (!radeon_update_wrapper(ctx, rrb, newImage)) {
562       _mesa_reference_renderbuffer(&att->Renderbuffer, NULL);
563       _mesa_render_texture(ctx, fb, att);
564       return;
565   }
566
567   DBG("Begin render texture tid %x tex=%u w=%d h=%d refcount=%d\n",
568       _glthread_GetID(),
569       att->Texture->Name, newImage->Width, newImage->Height,
570       rrb->base.RefCount);
571
572   /* point the renderbufer's region to the texture image region */
573   radeon_image = (radeon_texture_image *)newImage;
574   if (rrb->bo != radeon_image->mt->bo) {
575      if (rrb->bo)
576  	radeon_bo_unref(rrb->bo);
577      rrb->bo = radeon_image->mt->bo;
578      radeon_bo_ref(rrb->bo);
579   }
580
581   /* compute offset of the particular 2D image within the texture region */
582   imageOffset = radeon_miptree_image_offset(radeon_image->mt,
583                                            att->CubeMapFace,
584                                            att->TextureLevel);
585
586   if (att->Texture->Target == GL_TEXTURE_3D) {
587      imageOffset += radeon_image->mt->levels[att->TextureLevel].rowstride *
588                     radeon_image->mt->levels[att->TextureLevel].height *
589                     att->Zoffset;
590   }
591
592   /* store that offset in the region, along with the correct pitch for
593    * the image we are rendering to */
594   rrb->draw_offset = imageOffset;
595   rrb->pitch = radeon_image->mt->levels[att->TextureLevel].rowstride;
596
597   /* update drawing region, etc */
598   radeon_draw_buffer(ctx, fb);
599}
600
601static void
602radeon_finish_render_texture(GLcontext * ctx,
603                            struct gl_renderbuffer_attachment *att)
604{
605
606}
607static void
608radeon_validate_framebuffer(GLcontext *ctx, struct gl_framebuffer *fb)
609{
610}
611
612void radeon_fbo_init(struct radeon_context *radeon)
613{
614  radeon->glCtx->Driver.NewFramebuffer = radeon_new_framebuffer;
615  radeon->glCtx->Driver.NewRenderbuffer = radeon_new_renderbuffer;
616  radeon->glCtx->Driver.BindFramebuffer = radeon_bind_framebuffer;
617  radeon->glCtx->Driver.FramebufferRenderbuffer = radeon_framebuffer_renderbuffer;
618  radeon->glCtx->Driver.RenderTexture = radeon_render_texture;
619  radeon->glCtx->Driver.FinishRenderTexture = radeon_finish_render_texture;
620  radeon->glCtx->Driver.ResizeBuffers = radeon_resize_buffers;
621  radeon->glCtx->Driver.ValidateFramebuffer = radeon_validate_framebuffer;
622  radeon->glCtx->Driver.BlitFramebuffer = _mesa_meta_BlitFramebuffer;
623}
624
625
626void radeon_renderbuffer_set_bo(struct radeon_renderbuffer *rb,
627				struct radeon_bo *bo)
628{
629  struct radeon_bo *old;
630  old = rb->bo;
631  rb->bo = bo;
632  radeon_bo_ref(bo);
633  if (old)
634    radeon_bo_unref(old);
635}
636