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 36static GLboolean 37set_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 83static GLboolean 84nouveau_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 103static void 104nouveau_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 112static struct gl_renderbuffer * 113nouveau_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 130static void 131nouveau_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 bool flip_y) 138{ 139 struct nouveau_surface *s = &to_nouveau_renderbuffer(rb)->surface; 140 GLubyte *map; 141 int stride; 142 int flags = 0; 143 144 /* driver does not support GL_FRAMEBUFFER_FLIP_Y_MESA */ 145 assert((rb->Name == 0) == flip_y); 146 147 if (mode & GL_MAP_READ_BIT) 148 flags |= NOUVEAU_BO_RD; 149 if (mode & GL_MAP_WRITE_BIT) 150 flags |= NOUVEAU_BO_WR; 151 152 nouveau_bo_map(s->bo, flags, context_client(ctx)); 153 154 map = s->bo->map; 155 stride = s->pitch; 156 157 if (rb->Name == 0) { 158 map += stride * (rb->Height - 1); 159 stride = -stride; 160 } 161 162 map += x * s->cpp; 163 map += (int)y * stride; 164 165 *out_map = map; 166 *out_stride = stride; 167} 168 169static void 170nouveau_renderbuffer_unmap(struct gl_context *ctx, 171 struct gl_renderbuffer *rb) 172{ 173} 174 175static GLboolean 176nouveau_renderbuffer_dri_storage(struct gl_context *ctx, struct gl_renderbuffer *rb, 177 GLenum internalFormat, 178 GLuint width, GLuint height) 179{ 180 if (!set_renderbuffer_format(rb, internalFormat)) 181 return GL_FALSE; 182 183 rb->Width = width; 184 rb->Height = height; 185 186 return GL_TRUE; 187} 188 189struct gl_renderbuffer * 190nouveau_renderbuffer_dri_new(GLenum format, __DRIdrawable *drawable) 191{ 192 struct gl_renderbuffer *rb; 193 194 rb = nouveau_renderbuffer_new(NULL, 0); 195 if (!rb) 196 return NULL; 197 198 rb->AllocStorage = nouveau_renderbuffer_dri_storage; 199 200 if (!set_renderbuffer_format(rb, format)) { 201 nouveau_renderbuffer_del(NULL, rb); 202 return NULL; 203 } 204 205 return rb; 206} 207 208static struct gl_framebuffer * 209nouveau_framebuffer_new(struct gl_context *ctx, GLuint name) 210{ 211 struct nouveau_framebuffer *nfb; 212 213 nfb = CALLOC_STRUCT(nouveau_framebuffer); 214 if (!nfb) 215 return NULL; 216 217 _mesa_initialize_user_framebuffer(&nfb->base, name); 218 219 return &nfb->base; 220} 221 222struct gl_framebuffer * 223nouveau_framebuffer_dri_new(const struct gl_config *visual) 224{ 225 struct nouveau_framebuffer *nfb; 226 227 nfb = CALLOC_STRUCT(nouveau_framebuffer); 228 if (!nfb) 229 return NULL; 230 231 _mesa_initialize_window_framebuffer(&nfb->base, visual); 232 nfb->need_front = !visual->doubleBufferMode; 233 234 return &nfb->base; 235} 236 237static void 238nouveau_bind_framebuffer(struct gl_context *ctx, GLenum target, 239 struct gl_framebuffer *dfb, 240 struct gl_framebuffer *rfb) 241{ 242 context_dirty(ctx, FRAMEBUFFER); 243} 244 245static void 246nouveau_framebuffer_renderbuffer(struct gl_context *ctx, struct gl_framebuffer *fb, 247 GLenum attachment, struct gl_renderbuffer *rb) 248{ 249 _mesa_FramebufferRenderbuffer_sw(ctx, fb, attachment, rb); 250 251 context_dirty(ctx, FRAMEBUFFER); 252} 253 254static void 255nouveau_render_texture(struct gl_context *ctx, struct gl_framebuffer *fb, 256 struct gl_renderbuffer_attachment *att) 257{ 258 struct gl_renderbuffer *rb = att->Renderbuffer; 259 struct gl_texture_image *ti = rb->TexImage; 260 261 /* Update the renderbuffer fields from the texture. */ 262 nouveau_surface_ref(&to_nouveau_teximage(ti)->surface, 263 &to_nouveau_renderbuffer(rb)->surface); 264 265 context_dirty(ctx, FRAMEBUFFER); 266} 267 268static void 269nouveau_finish_render_texture(struct gl_context *ctx, 270 struct gl_renderbuffer *rb) 271{ 272 if (rb && rb->TexImage) 273 texture_dirty(rb->TexImage->TexObject); 274} 275 276static int 277validate_format_bpp(mesa_format format) 278{ 279 switch (format) { 280 case MESA_FORMAT_B8G8R8X8_UNORM: 281 case MESA_FORMAT_B8G8R8A8_UNORM: 282 case MESA_FORMAT_S8_UINT_Z24_UNORM: 283 return 32; 284 case MESA_FORMAT_B5G6R5_UNORM: 285 case MESA_FORMAT_Z_UNORM16: 286 return 16; 287 default: 288 return 0; 289 } 290} 291 292static void 293nouveau_check_framebuffer_complete(struct gl_context *ctx, 294 struct gl_framebuffer *fb) 295{ 296 struct gl_renderbuffer_attachment *color = 297 &fb->Attachment[BUFFER_COLOR0]; 298 struct gl_renderbuffer_attachment *depth = 299 &fb->Attachment[BUFFER_DEPTH]; 300 int color_bpp = 0, zeta_bpp; 301 302 if (color->Type == GL_TEXTURE) { 303 color_bpp = validate_format_bpp( 304 color->Renderbuffer->TexImage->TexFormat); 305 if (!color_bpp) 306 goto err; 307 } 308 309 if (depth->Type == GL_TEXTURE) { 310 zeta_bpp = validate_format_bpp( 311 depth->Renderbuffer->TexImage->TexFormat); 312 if (!zeta_bpp) 313 goto err; 314 /* NV04/NV05 requires same bpp-ness for color/zeta */ 315 if (context_chipset(ctx) < 0x10 && 316 color_bpp && color_bpp != zeta_bpp) 317 goto err; 318 } 319 320 return; 321err: 322 fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT; 323 return; 324} 325 326void 327nouveau_fbo_functions_init(struct dd_function_table *functions) 328{ 329 functions->NewFramebuffer = nouveau_framebuffer_new; 330 functions->NewRenderbuffer = nouveau_renderbuffer_new; 331 functions->MapRenderbuffer = nouveau_renderbuffer_map; 332 functions->UnmapRenderbuffer = nouveau_renderbuffer_unmap; 333 functions->BindFramebuffer = nouveau_bind_framebuffer; 334 functions->FramebufferRenderbuffer = nouveau_framebuffer_renderbuffer; 335 functions->RenderTexture = nouveau_render_texture; 336 functions->FinishRenderTexture = nouveau_finish_render_texture; 337 functions->ValidateFramebuffer = nouveau_check_framebuffer_complete; 338} 339