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 "main/mfeatures.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_XRGB8888; 49 s->cpp = 4; 50 break; 51 case GL_RGBA: 52 case GL_RGBA8: 53 rb->_BaseFormat = GL_RGBA; 54 rb->Format = MESA_FORMAT_ARGB8888; 55 s->cpp = 4; 56 break; 57 case GL_RGB5: 58 rb->_BaseFormat = GL_RGB; 59 rb->Format = MESA_FORMAT_RGB565; 60 s->cpp = 2; 61 break; 62 case GL_DEPTH_COMPONENT16: 63 rb->_BaseFormat = GL_DEPTH_COMPONENT; 64 rb->Format = MESA_FORMAT_Z16; 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_Z24_S8; 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{ 139 struct nouveau_surface *s = &to_nouveau_renderbuffer(rb)->surface; 140 GLubyte *map; 141 int stride; 142 int flags = 0; 143 144 if (mode & GL_MAP_READ_BIT) 145 flags |= NOUVEAU_BO_RD; 146 if (mode & GL_MAP_WRITE_BIT) 147 flags |= NOUVEAU_BO_WR; 148 149 nouveau_bo_map(s->bo, flags, context_client(ctx)); 150 151 map = s->bo->map; 152 stride = s->pitch; 153 154 if (rb->Name == 0) { 155 map += stride * (rb->Height - 1); 156 stride = -stride; 157 } 158 159 map += x * s->cpp; 160 map += (int)y * stride; 161 162 *out_map = map; 163 *out_stride = stride; 164} 165 166static void 167nouveau_renderbuffer_unmap(struct gl_context *ctx, 168 struct gl_renderbuffer *rb) 169{ 170} 171 172static GLboolean 173nouveau_renderbuffer_dri_storage(struct gl_context *ctx, struct gl_renderbuffer *rb, 174 GLenum internalFormat, 175 GLuint width, GLuint height) 176{ 177 if (!set_renderbuffer_format(rb, internalFormat)) 178 return GL_FALSE; 179 180 rb->Width = width; 181 rb->Height = height; 182 183 return GL_TRUE; 184} 185 186struct gl_renderbuffer * 187nouveau_renderbuffer_dri_new(GLenum format, __DRIdrawable *drawable) 188{ 189 struct gl_renderbuffer *rb; 190 191 rb = nouveau_renderbuffer_new(NULL, 0); 192 if (!rb) 193 return NULL; 194 195 rb->AllocStorage = nouveau_renderbuffer_dri_storage; 196 197 if (!set_renderbuffer_format(rb, format)) { 198 nouveau_renderbuffer_del(NULL, rb); 199 return NULL; 200 } 201 202 return rb; 203} 204 205static struct gl_framebuffer * 206nouveau_framebuffer_new(struct gl_context *ctx, GLuint name) 207{ 208 struct nouveau_framebuffer *nfb; 209 210 nfb = CALLOC_STRUCT(nouveau_framebuffer); 211 if (!nfb) 212 return NULL; 213 214 _mesa_initialize_user_framebuffer(&nfb->base, name); 215 216 return &nfb->base; 217} 218 219struct gl_framebuffer * 220nouveau_framebuffer_dri_new(const struct gl_config *visual) 221{ 222 struct nouveau_framebuffer *nfb; 223 224 nfb = CALLOC_STRUCT(nouveau_framebuffer); 225 if (!nfb) 226 return NULL; 227 228 _mesa_initialize_window_framebuffer(&nfb->base, visual); 229 nfb->need_front = !visual->doubleBufferMode; 230 231 return &nfb->base; 232} 233 234static void 235nouveau_bind_framebuffer(struct gl_context *ctx, GLenum target, 236 struct gl_framebuffer *dfb, 237 struct gl_framebuffer *rfb) 238{ 239 context_dirty(ctx, FRAMEBUFFER); 240} 241 242static void 243nouveau_framebuffer_renderbuffer(struct gl_context *ctx, struct gl_framebuffer *fb, 244 GLenum attachment, struct gl_renderbuffer *rb) 245{ 246 _mesa_framebuffer_renderbuffer(ctx, fb, attachment, rb); 247 248 context_dirty(ctx, FRAMEBUFFER); 249} 250 251static GLenum 252get_tex_format(struct gl_texture_image *ti) 253{ 254 switch (ti->TexFormat) { 255 case MESA_FORMAT_ARGB8888: 256 return GL_RGBA8; 257 case MESA_FORMAT_XRGB8888: 258 return GL_RGB8; 259 case MESA_FORMAT_RGB565: 260 return GL_RGB5; 261 default: 262 return GL_NONE; 263 } 264} 265 266static void 267nouveau_render_texture(struct gl_context *ctx, struct gl_framebuffer *fb, 268 struct gl_renderbuffer_attachment *att) 269{ 270 struct gl_renderbuffer *rb = att->Renderbuffer; 271 struct gl_texture_image *ti = 272 att->Texture->Image[att->CubeMapFace][att->TextureLevel]; 273 274 /* Allocate a renderbuffer object for the texture if we 275 * haven't already done so. */ 276 if (!rb) { 277 rb = nouveau_renderbuffer_new(ctx, ~0); 278 assert(rb); 279 280 rb->AllocStorage = NULL; 281 _mesa_reference_renderbuffer(&att->Renderbuffer, rb); 282 } 283 284 /* Update the renderbuffer fields from the texture. */ 285 set_renderbuffer_format(rb, get_tex_format(ti)); 286 rb->Width = ti->Width; 287 rb->Height = ti->Height; 288 nouveau_surface_ref(&to_nouveau_teximage(ti)->surface, 289 &to_nouveau_renderbuffer(rb)->surface); 290 291 context_dirty(ctx, FRAMEBUFFER); 292} 293 294static void 295nouveau_finish_render_texture(struct gl_context *ctx, 296 struct gl_renderbuffer_attachment *att) 297{ 298 texture_dirty(att->Texture); 299} 300 301void 302nouveau_fbo_functions_init(struct dd_function_table *functions) 303{ 304#if FEATURE_EXT_framebuffer_object 305 functions->NewFramebuffer = nouveau_framebuffer_new; 306 functions->NewRenderbuffer = nouveau_renderbuffer_new; 307 functions->MapRenderbuffer = nouveau_renderbuffer_map; 308 functions->UnmapRenderbuffer = nouveau_renderbuffer_unmap; 309 functions->BindFramebuffer = nouveau_bind_framebuffer; 310 functions->FramebufferRenderbuffer = nouveau_framebuffer_renderbuffer; 311 functions->RenderTexture = nouveau_render_texture; 312 functions->FinishRenderTexture = nouveau_finish_render_texture; 313#endif 314} 315