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#include "util/u_memory.h" 36 37static GLboolean 38set_renderbuffer_format(struct gl_renderbuffer *rb, GLenum internalFormat) 39{ 40 struct nouveau_surface *s = &to_nouveau_renderbuffer(rb)->surface; 41 42 rb->InternalFormat = internalFormat; 43 44 switch (internalFormat) { 45 case GL_RGB: 46 case GL_RGB8: 47 rb->_BaseFormat = GL_RGB; 48 rb->Format = MESA_FORMAT_B8G8R8X8_UNORM; 49 s->cpp = 4; 50 break; 51 case GL_RGBA: 52 case GL_RGBA8: 53 rb->_BaseFormat = GL_RGBA; 54 rb->Format = MESA_FORMAT_B8G8R8A8_UNORM; 55 s->cpp = 4; 56 break; 57 case GL_RGB5: 58 rb->_BaseFormat = GL_RGB; 59 rb->Format = MESA_FORMAT_B5G6R5_UNORM; 60 s->cpp = 2; 61 break; 62 case GL_DEPTH_COMPONENT16: 63 rb->_BaseFormat = GL_DEPTH_COMPONENT; 64 rb->Format = MESA_FORMAT_Z_UNORM16; 65 s->cpp = 2; 66 break; 67 case GL_DEPTH_COMPONENT: 68 case GL_DEPTH_COMPONENT24: 69 case GL_STENCIL_INDEX8_EXT: 70 case GL_DEPTH24_STENCIL8_EXT: 71 rb->_BaseFormat = GL_DEPTH_STENCIL; 72 rb->Format = MESA_FORMAT_S8_UINT_Z24_UNORM; 73 s->cpp = 4; 74 break; 75 default: 76 return GL_FALSE; 77 } 78 79 s->format = rb->Format; 80 81 return GL_TRUE; 82} 83 84static GLboolean 85nouveau_renderbuffer_storage(struct gl_context *ctx, struct gl_renderbuffer *rb, 86 GLenum internalFormat, 87 GLuint width, GLuint height) 88{ 89 struct nouveau_surface *s = &to_nouveau_renderbuffer(rb)->surface; 90 91 if (!set_renderbuffer_format(rb, internalFormat)) 92 return GL_FALSE; 93 94 rb->Width = width; 95 rb->Height = height; 96 97 nouveau_surface_alloc(ctx, s, TILED, NOUVEAU_BO_VRAM | NOUVEAU_BO_MAP, 98 rb->Format, width, height); 99 100 context_dirty(ctx, FRAMEBUFFER); 101 return GL_TRUE; 102} 103 104static void 105nouveau_renderbuffer_del(struct gl_context *ctx, struct gl_renderbuffer *rb) 106{ 107 struct nouveau_surface *s = &to_nouveau_renderbuffer(rb)->surface; 108 109 nouveau_surface_ref(NULL, s); 110 _mesa_delete_renderbuffer(ctx, rb); 111} 112 113static struct gl_renderbuffer * 114nouveau_renderbuffer_new(struct gl_context *ctx, GLuint name) 115{ 116 struct gl_renderbuffer *rb; 117 118 rb = (struct gl_renderbuffer *) 119 CALLOC_STRUCT(nouveau_renderbuffer); 120 if (!rb) 121 return NULL; 122 123 _mesa_init_renderbuffer(rb, name); 124 125 rb->AllocStorage = nouveau_renderbuffer_storage; 126 rb->Delete = nouveau_renderbuffer_del; 127 128 return rb; 129} 130 131static void 132nouveau_renderbuffer_map(struct gl_context *ctx, 133 struct gl_renderbuffer *rb, 134 GLuint x, GLuint y, GLuint w, GLuint h, 135 GLbitfield mode, 136 GLubyte **out_map, 137 GLint *out_stride, 138 bool flip_y) 139{ 140 struct nouveau_surface *s = &to_nouveau_renderbuffer(rb)->surface; 141 GLubyte *map; 142 int stride; 143 int flags = 0; 144 145 /* driver does not support GL_FRAMEBUFFER_FLIP_Y_MESA */ 146 assert((rb->Name == 0) == flip_y); 147 148 if (mode & GL_MAP_READ_BIT) 149 flags |= NOUVEAU_BO_RD; 150 if (mode & GL_MAP_WRITE_BIT) 151 flags |= NOUVEAU_BO_WR; 152 153 nouveau_bo_map(s->bo, flags, context_client(ctx)); 154 155 map = s->bo->map; 156 stride = s->pitch; 157 158 if (rb->Name == 0) { 159 map += stride * (rb->Height - 1); 160 stride = -stride; 161 } 162 163 map += x * s->cpp; 164 map += (int)y * stride; 165 166 *out_map = map; 167 *out_stride = stride; 168} 169 170static void 171nouveau_renderbuffer_unmap(struct gl_context *ctx, 172 struct gl_renderbuffer *rb) 173{ 174} 175 176static GLboolean 177nouveau_renderbuffer_dri_storage(struct gl_context *ctx, struct gl_renderbuffer *rb, 178 GLenum internalFormat, 179 GLuint width, GLuint height) 180{ 181 if (!set_renderbuffer_format(rb, internalFormat)) 182 return GL_FALSE; 183 184 rb->Width = width; 185 rb->Height = height; 186 187 return GL_TRUE; 188} 189 190struct gl_renderbuffer * 191nouveau_renderbuffer_dri_new(GLenum format, __DRIdrawable *drawable) 192{ 193 struct gl_renderbuffer *rb; 194 195 rb = nouveau_renderbuffer_new(NULL, 0); 196 if (!rb) 197 return NULL; 198 199 rb->AllocStorage = nouveau_renderbuffer_dri_storage; 200 201 if (!set_renderbuffer_format(rb, format)) { 202 nouveau_renderbuffer_del(NULL, rb); 203 return NULL; 204 } 205 206 return rb; 207} 208 209static struct gl_framebuffer * 210nouveau_framebuffer_new(struct gl_context *ctx, GLuint name) 211{ 212 struct nouveau_framebuffer *nfb; 213 214 nfb = CALLOC_STRUCT(nouveau_framebuffer); 215 if (!nfb) 216 return NULL; 217 218 _mesa_initialize_user_framebuffer(&nfb->base, name); 219 220 return &nfb->base; 221} 222 223struct gl_framebuffer * 224nouveau_framebuffer_dri_new(const struct gl_config *visual) 225{ 226 struct nouveau_framebuffer *nfb; 227 228 nfb = CALLOC_STRUCT(nouveau_framebuffer); 229 if (!nfb) 230 return NULL; 231 232 _mesa_initialize_window_framebuffer(&nfb->base, visual); 233 nfb->need_front = !visual->doubleBufferMode; 234 235 return &nfb->base; 236} 237 238static void 239nouveau_bind_framebuffer(struct gl_context *ctx, GLenum target, 240 struct gl_framebuffer *dfb, 241 struct gl_framebuffer *rfb) 242{ 243 context_dirty(ctx, FRAMEBUFFER); 244} 245 246static void 247nouveau_framebuffer_renderbuffer(struct gl_context *ctx, struct gl_framebuffer *fb, 248 GLenum attachment, struct gl_renderbuffer *rb) 249{ 250 _mesa_FramebufferRenderbuffer_sw(ctx, fb, attachment, rb); 251 252 context_dirty(ctx, FRAMEBUFFER); 253} 254 255static void 256nouveau_render_texture(struct gl_context *ctx, struct gl_framebuffer *fb, 257 struct gl_renderbuffer_attachment *att) 258{ 259 struct gl_renderbuffer *rb = att->Renderbuffer; 260 struct gl_texture_image *ti = rb->TexImage; 261 262 /* Update the renderbuffer fields from the texture. */ 263 nouveau_surface_ref(&to_nouveau_teximage(ti)->surface, 264 &to_nouveau_renderbuffer(rb)->surface); 265 266 context_dirty(ctx, FRAMEBUFFER); 267} 268 269static void 270nouveau_finish_render_texture(struct gl_context *ctx, 271 struct gl_renderbuffer *rb) 272{ 273 if (rb && rb->TexImage) 274 texture_dirty(rb->TexImage->TexObject); 275} 276 277static int 278validate_format_bpp(mesa_format format) 279{ 280 switch (format) { 281 case MESA_FORMAT_B8G8R8X8_UNORM: 282 case MESA_FORMAT_B8G8R8A8_UNORM: 283 case MESA_FORMAT_S8_UINT_Z24_UNORM: 284 return 32; 285 case MESA_FORMAT_B5G6R5_UNORM: 286 case MESA_FORMAT_Z_UNORM16: 287 return 16; 288 default: 289 return 0; 290 } 291} 292 293static void 294nouveau_check_framebuffer_complete(struct gl_context *ctx, 295 struct gl_framebuffer *fb) 296{ 297 struct gl_renderbuffer_attachment *color = 298 &fb->Attachment[BUFFER_COLOR0]; 299 struct gl_renderbuffer_attachment *depth = 300 &fb->Attachment[BUFFER_DEPTH]; 301 int color_bpp = 0, zeta_bpp; 302 303 if (color->Type == GL_TEXTURE) { 304 color_bpp = validate_format_bpp( 305 color->Renderbuffer->TexImage->TexFormat); 306 if (!color_bpp) 307 goto err; 308 } 309 310 if (depth->Type == GL_TEXTURE) { 311 zeta_bpp = validate_format_bpp( 312 depth->Renderbuffer->TexImage->TexFormat); 313 if (!zeta_bpp) 314 goto err; 315 /* NV04/NV05 requires same bpp-ness for color/zeta */ 316 if (context_chipset(ctx) < 0x10 && 317 color_bpp && color_bpp != zeta_bpp) 318 goto err; 319 } 320 321 return; 322err: 323 fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT; 324 return; 325} 326 327void 328nouveau_fbo_functions_init(struct dd_function_table *functions) 329{ 330 functions->NewFramebuffer = nouveau_framebuffer_new; 331 functions->NewRenderbuffer = nouveau_renderbuffer_new; 332 functions->MapRenderbuffer = nouveau_renderbuffer_map; 333 functions->UnmapRenderbuffer = nouveau_renderbuffer_unmap; 334 functions->BindFramebuffer = nouveau_bind_framebuffer; 335 functions->FramebufferRenderbuffer = nouveau_framebuffer_renderbuffer; 336 functions->RenderTexture = nouveau_render_texture; 337 functions->FinishRenderTexture = nouveau_finish_render_texture; 338 functions->ValidateFramebuffer = nouveau_check_framebuffer_complete; 339} 340