Home | History | Annotate | Download | only in nouveau
      1 /*
      2  * Copyright (C) 2009 Francisco Jerez.
      3  * All Rights Reserved.
      4  *
      5  * Permission is hereby granted, free of charge, to any person obtaining
      6  * a copy of this software and associated documentation files (the
      7  * "Software"), to deal in the Software without restriction, including
      8  * without limitation the rights to use, copy, modify, merge, publish,
      9  * distribute, sublicense, and/or sell copies of the Software, and to
     10  * permit persons to whom the Software is furnished to do so, subject to
     11  * the following conditions:
     12  *
     13  * The above copyright notice and this permission notice (including the
     14  * next paragraph) shall be included in all copies or substantial
     15  * portions of the Software.
     16  *
     17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     18  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
     20  * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
     21  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
     22  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
     23  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     24  *
     25  */
     26 
     27 #include "nouveau_driver.h"
     28 #include "nouveau_fbo.h"
     29 #include "nouveau_context.h"
     30 #include "nouveau_texture.h"
     31 
     32 #include "main/framebuffer.h"
     33 #include "main/renderbuffer.h"
     34 #include "main/fbobject.h"
     35 
     36 static GLboolean
     37 set_renderbuffer_format(struct gl_renderbuffer *rb, GLenum internalFormat)
     38 {
     39 	struct nouveau_surface *s = &to_nouveau_renderbuffer(rb)->surface;
     40 
     41 	rb->InternalFormat  = internalFormat;
     42 
     43 	switch (internalFormat) {
     44 	case GL_RGB:
     45 	case GL_RGB8:
     46 		rb->_BaseFormat  = GL_RGB;
     47 		rb->Format = MESA_FORMAT_B8G8R8X8_UNORM;
     48 		s->cpp = 4;
     49 		break;
     50 	case GL_RGBA:
     51 	case GL_RGBA8:
     52 		rb->_BaseFormat  = GL_RGBA;
     53 		rb->Format = MESA_FORMAT_B8G8R8A8_UNORM;
     54 		s->cpp = 4;
     55 		break;
     56 	case GL_RGB5:
     57 		rb->_BaseFormat  = GL_RGB;
     58 		rb->Format = MESA_FORMAT_B5G6R5_UNORM;
     59 		s->cpp = 2;
     60 		break;
     61 	case GL_DEPTH_COMPONENT16:
     62 		rb->_BaseFormat  = GL_DEPTH_COMPONENT;
     63 		rb->Format = MESA_FORMAT_Z_UNORM16;
     64 		s->cpp = 2;
     65 		break;
     66 	case GL_DEPTH_COMPONENT:
     67 	case GL_DEPTH_COMPONENT24:
     68 	case GL_STENCIL_INDEX8_EXT:
     69 	case GL_DEPTH24_STENCIL8_EXT:
     70 		rb->_BaseFormat  = GL_DEPTH_STENCIL;
     71 		rb->Format = MESA_FORMAT_S8_UINT_Z24_UNORM;
     72 		s->cpp = 4;
     73 		break;
     74 	default:
     75 		return GL_FALSE;
     76 	}
     77 
     78 	s->format = rb->Format;
     79 
     80 	return GL_TRUE;
     81 }
     82 
     83 static GLboolean
     84 nouveau_renderbuffer_storage(struct gl_context *ctx, struct gl_renderbuffer *rb,
     85 			     GLenum internalFormat,
     86 			     GLuint width, GLuint height)
     87 {
     88 	struct nouveau_surface *s = &to_nouveau_renderbuffer(rb)->surface;
     89 
     90 	if (!set_renderbuffer_format(rb, internalFormat))
     91 		return GL_FALSE;
     92 
     93 	rb->Width = width;
     94 	rb->Height = height;
     95 
     96 	nouveau_surface_alloc(ctx, s, TILED, NOUVEAU_BO_VRAM | NOUVEAU_BO_MAP,
     97 			      rb->Format, width, height);
     98 
     99 	context_dirty(ctx, FRAMEBUFFER);
    100 	return GL_TRUE;
    101 }
    102 
    103 static void
    104 nouveau_renderbuffer_del(struct gl_context *ctx, struct gl_renderbuffer *rb)
    105 {
    106 	struct nouveau_surface *s = &to_nouveau_renderbuffer(rb)->surface;
    107 
    108 	nouveau_surface_ref(NULL, s);
    109 	_mesa_delete_renderbuffer(ctx, rb);
    110 }
    111 
    112 static struct gl_renderbuffer *
    113 nouveau_renderbuffer_new(struct gl_context *ctx, GLuint name)
    114 {
    115 	struct gl_renderbuffer *rb;
    116 
    117 	rb = (struct gl_renderbuffer *)
    118 		CALLOC_STRUCT(nouveau_renderbuffer);
    119 	if (!rb)
    120 		return NULL;
    121 
    122 	_mesa_init_renderbuffer(rb, name);
    123 
    124 	rb->AllocStorage = nouveau_renderbuffer_storage;
    125 	rb->Delete = nouveau_renderbuffer_del;
    126 
    127 	return rb;
    128 }
    129 
    130 static void
    131 nouveau_renderbuffer_map(struct gl_context *ctx,
    132 			 struct gl_renderbuffer *rb,
    133 			 GLuint x, GLuint y, GLuint w, GLuint h,
    134 			 GLbitfield mode,
    135 			 GLubyte **out_map,
    136 			 GLint *out_stride)
    137 {
    138 	struct nouveau_surface *s = &to_nouveau_renderbuffer(rb)->surface;
    139 	GLubyte *map;
    140 	int stride;
    141 	int flags = 0;
    142 
    143 	if (mode & GL_MAP_READ_BIT)
    144 		flags |= NOUVEAU_BO_RD;
    145 	if (mode & GL_MAP_WRITE_BIT)
    146 		flags |= NOUVEAU_BO_WR;
    147 
    148 	nouveau_bo_map(s->bo, flags, context_client(ctx));
    149 
    150 	map = s->bo->map;
    151 	stride = s->pitch;
    152 
    153 	if (rb->Name == 0) {
    154 		map += stride * (rb->Height - 1);
    155 		stride = -stride;
    156 	}
    157 
    158 	map += x * s->cpp;
    159 	map += (int)y * stride;
    160 
    161 	*out_map = map;
    162 	*out_stride = stride;
    163 }
    164 
    165 static void
    166 nouveau_renderbuffer_unmap(struct gl_context *ctx,
    167 			   struct gl_renderbuffer *rb)
    168 {
    169 }
    170 
    171 static GLboolean
    172 nouveau_renderbuffer_dri_storage(struct gl_context *ctx, struct gl_renderbuffer *rb,
    173 				 GLenum internalFormat,
    174 				 GLuint width, GLuint height)
    175 {
    176 	if (!set_renderbuffer_format(rb, internalFormat))
    177 		return GL_FALSE;
    178 
    179 	rb->Width = width;
    180 	rb->Height = height;
    181 
    182 	return GL_TRUE;
    183 }
    184 
    185 struct gl_renderbuffer *
    186 nouveau_renderbuffer_dri_new(GLenum format, __DRIdrawable *drawable)
    187 {
    188 	struct gl_renderbuffer *rb;
    189 
    190 	rb = nouveau_renderbuffer_new(NULL, 0);
    191 	if (!rb)
    192 		return NULL;
    193 
    194 	rb->AllocStorage = nouveau_renderbuffer_dri_storage;
    195 
    196 	if (!set_renderbuffer_format(rb, format)) {
    197 		nouveau_renderbuffer_del(NULL, rb);
    198 		return NULL;
    199 	}
    200 
    201 	return rb;
    202 }
    203 
    204 static struct gl_framebuffer *
    205 nouveau_framebuffer_new(struct gl_context *ctx, GLuint name)
    206 {
    207 	struct nouveau_framebuffer *nfb;
    208 
    209 	nfb = CALLOC_STRUCT(nouveau_framebuffer);
    210 	if (!nfb)
    211 		return NULL;
    212 
    213 	_mesa_initialize_user_framebuffer(&nfb->base, name);
    214 
    215 	return &nfb->base;
    216 }
    217 
    218 struct gl_framebuffer *
    219 nouveau_framebuffer_dri_new(const struct gl_config *visual)
    220 {
    221 	struct nouveau_framebuffer *nfb;
    222 
    223 	nfb = CALLOC_STRUCT(nouveau_framebuffer);
    224 	if (!nfb)
    225 		return NULL;
    226 
    227 	_mesa_initialize_window_framebuffer(&nfb->base, visual);
    228 	nfb->need_front = !visual->doubleBufferMode;
    229 
    230 	return &nfb->base;
    231 }
    232 
    233 static void
    234 nouveau_bind_framebuffer(struct gl_context *ctx, GLenum target,
    235 			 struct gl_framebuffer *dfb,
    236 			 struct gl_framebuffer *rfb)
    237 {
    238 	context_dirty(ctx, FRAMEBUFFER);
    239 }
    240 
    241 static void
    242 nouveau_framebuffer_renderbuffer(struct gl_context *ctx, struct gl_framebuffer *fb,
    243 				 GLenum attachment, struct gl_renderbuffer *rb)
    244 {
    245 	_mesa_FramebufferRenderbuffer_sw(ctx, fb, attachment, rb);
    246 
    247 	context_dirty(ctx, FRAMEBUFFER);
    248 }
    249 
    250 static void
    251 nouveau_render_texture(struct gl_context *ctx, struct gl_framebuffer *fb,
    252 		       struct gl_renderbuffer_attachment *att)
    253 {
    254 	struct gl_renderbuffer *rb = att->Renderbuffer;
    255 	struct gl_texture_image *ti = rb->TexImage;
    256 
    257 	/* Update the renderbuffer fields from the texture. */
    258 	nouveau_surface_ref(&to_nouveau_teximage(ti)->surface,
    259 			    &to_nouveau_renderbuffer(rb)->surface);
    260 
    261 	context_dirty(ctx, FRAMEBUFFER);
    262 }
    263 
    264 static void
    265 nouveau_finish_render_texture(struct gl_context *ctx,
    266 			      struct gl_renderbuffer *rb)
    267 {
    268 	if (rb && rb->TexImage)
    269 		texture_dirty(rb->TexImage->TexObject);
    270 }
    271 
    272 static int
    273 validate_format_bpp(mesa_format format)
    274 {
    275 	switch (format) {
    276 	case MESA_FORMAT_B8G8R8X8_UNORM:
    277 	case MESA_FORMAT_B8G8R8A8_UNORM:
    278 	case MESA_FORMAT_S8_UINT_Z24_UNORM:
    279 		return 32;
    280 	case MESA_FORMAT_B5G6R5_UNORM:
    281 	case MESA_FORMAT_Z_UNORM16:
    282 		return 16;
    283 	default:
    284 		return 0;
    285 	}
    286 }
    287 
    288 static void
    289 nouveau_check_framebuffer_complete(struct gl_context *ctx,
    290 				   struct gl_framebuffer *fb)
    291 {
    292 	struct gl_renderbuffer_attachment *color =
    293 		&fb->Attachment[BUFFER_COLOR0];
    294 	struct gl_renderbuffer_attachment *depth =
    295 		&fb->Attachment[BUFFER_DEPTH];
    296 	int color_bpp = 0, zeta_bpp;
    297 
    298 	if (color->Type == GL_TEXTURE) {
    299 		color_bpp = validate_format_bpp(
    300 				color->Renderbuffer->TexImage->TexFormat);
    301 		if (!color_bpp)
    302 			goto err;
    303 	}
    304 
    305 	if (depth->Type == GL_TEXTURE) {
    306 		zeta_bpp = validate_format_bpp(
    307 				depth->Renderbuffer->TexImage->TexFormat);
    308 		if (!zeta_bpp)
    309 			goto err;
    310 		/* NV04/NV05 requires same bpp-ness for color/zeta */
    311 		if (context_chipset(ctx) < 0x10 &&
    312 		    color_bpp && color_bpp != zeta_bpp)
    313 			goto err;
    314 	}
    315 
    316 	return;
    317 err:
    318 	fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT;
    319 	return;
    320 }
    321 
    322 void
    323 nouveau_fbo_functions_init(struct dd_function_table *functions)
    324 {
    325 	functions->NewFramebuffer = nouveau_framebuffer_new;
    326 	functions->NewRenderbuffer = nouveau_renderbuffer_new;
    327 	functions->MapRenderbuffer = nouveau_renderbuffer_map;
    328 	functions->UnmapRenderbuffer = nouveau_renderbuffer_unmap;
    329 	functions->BindFramebuffer = nouveau_bind_framebuffer;
    330 	functions->FramebufferRenderbuffer = nouveau_framebuffer_renderbuffer;
    331 	functions->RenderTexture = nouveau_render_texture;
    332 	functions->FinishRenderTexture = nouveau_finish_render_texture;
    333 	functions->ValidateFramebuffer = nouveau_check_framebuffer_complete;
    334 }
    335