Merge branch '7.8'
[mesa.git] / src / mesa / drivers / dri / nouveau / nouveau_fbo.c
index 23525509d14388192d8762d8ff71acaa34f14854..8be7edb150bf8bbde835eed86ee0ecdcf3fd9a37 100644 (file)
-#include "utils.h"
-#include "framebuffer.h"
-#include "renderbuffer.h"
-#include "fbobject.h"
-
-#include "nouveau_context.h"
+/*
+ * Copyright (C) 2009 Francisco Jerez.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "nouveau_driver.h"
 #include "nouveau_fbo.h"
-#include "nouveau_fifo.h"
-#include "nouveau_msg.h"
-#include "nouveau_object.h"
-#include "nouveau_reg.h"
+#include "nouveau_context.h"
+#include "nouveau_texture.h"
+
+#include "main/framebuffer.h"
+#include "main/renderbuffer.h"
+#include "main/fbobject.h"
 
 static GLboolean
-nouveau_renderbuffer_pixelformat(nouveau_renderbuffer_t * nrb,
-                                GLenum internalFormat)
+set_renderbuffer_format(struct gl_renderbuffer *rb, GLenum internalFormat)
 {
-       nrb->mesa.InternalFormat = internalFormat;
+       struct nouveau_surface *s = &to_nouveau_renderbuffer(rb)->surface;
+
+       rb->InternalFormat  = internalFormat;
 
-       /*TODO: We probably want to extend this a bit, and maybe make
-        *      card-specific? 
-        */
        switch (internalFormat) {
+       case GL_RGB:
+       case GL_RGB8:
+               rb->_BaseFormat  = GL_RGB;
+               rb->Format = MESA_FORMAT_XRGB8888;
+               rb->DataType = GL_UNSIGNED_BYTE;
+               s->cpp = 4;
+               break;
        case GL_RGBA:
        case GL_RGBA8:
-               nrb->mesa._BaseFormat = GL_RGBA;
-               nrb->mesa._ActualFormat = GL_RGBA8;
-               nrb->mesa.DataType = GL_UNSIGNED_BYTE;
-               nrb->mesa.RedBits = 8;
-               nrb->mesa.GreenBits = 8;
-               nrb->mesa.BlueBits = 8;
-               nrb->mesa.AlphaBits = 8;
-               nrb->cpp = 4;
+               rb->_BaseFormat  = GL_RGBA;
+               rb->Format = MESA_FORMAT_ARGB8888;
+               rb->DataType = GL_UNSIGNED_BYTE;
+               s->cpp = 4;
                break;
-       case GL_RGB:
        case GL_RGB5:
-               nrb->mesa._BaseFormat = GL_RGB;
-               nrb->mesa._ActualFormat = GL_RGB5;
-               nrb->mesa.DataType = GL_UNSIGNED_BYTE;
-               nrb->mesa.RedBits = 5;
-               nrb->mesa.GreenBits = 6;
-               nrb->mesa.BlueBits = 5;
-               nrb->mesa.AlphaBits = 0;
-               nrb->cpp = 2;
+               rb->_BaseFormat  = GL_RGB;
+               rb->Format = MESA_FORMAT_RGB565;
+               rb->DataType = GL_UNSIGNED_BYTE;
+               s->cpp = 2;
                break;
        case GL_DEPTH_COMPONENT16:
-               nrb->mesa._BaseFormat = GL_DEPTH_COMPONENT;
-               nrb->mesa._ActualFormat = GL_DEPTH_COMPONENT16;
-               nrb->mesa.DataType = GL_UNSIGNED_SHORT;
-               nrb->mesa.DepthBits = 16;
-               nrb->cpp = 2;
+               rb->_BaseFormat  = GL_DEPTH_COMPONENT;
+               rb->Format = MESA_FORMAT_Z16;
+               rb->DataType = GL_UNSIGNED_SHORT;
+               s->cpp = 2;
                break;
        case GL_DEPTH_COMPONENT24:
-               nrb->mesa._BaseFormat = GL_DEPTH_COMPONENT;
-               nrb->mesa._ActualFormat = GL_DEPTH24_STENCIL8_EXT;
-               nrb->mesa.DataType = GL_UNSIGNED_INT_24_8_EXT;
-               nrb->mesa.DepthBits = 24;
-               nrb->cpp = 4;
-               break;
        case GL_STENCIL_INDEX8_EXT:
-               nrb->mesa._BaseFormat = GL_STENCIL_INDEX;
-               nrb->mesa._ActualFormat = GL_DEPTH24_STENCIL8_EXT;
-               nrb->mesa.DataType = GL_UNSIGNED_INT_24_8_EXT;
-               nrb->mesa.StencilBits = 8;
-               nrb->cpp = 4;
-               break;
        case GL_DEPTH24_STENCIL8_EXT:
-               nrb->mesa._BaseFormat = GL_DEPTH_STENCIL_EXT;
-               nrb->mesa._ActualFormat = GL_DEPTH24_STENCIL8_EXT;
-               nrb->mesa.DataType = GL_UNSIGNED_INT_24_8_EXT;
-               nrb->mesa.DepthBits = 24;
-               nrb->mesa.StencilBits = 8;
-               nrb->cpp = 4;
+               rb->_BaseFormat  = GL_DEPTH_STENCIL;
+               rb->Format = MESA_FORMAT_Z24_S8;
+               rb->DataType = GL_UNSIGNED_INT_24_8_EXT;
+               s->cpp = 4;
                break;
        default:
                return GL_FALSE;
-               break;
        }
 
+       s->format = rb->Format;
+
        return GL_TRUE;
 }
 
 static GLboolean
-nouveau_renderbuffer_storage(GLcontext * ctx, struct gl_renderbuffer *rb,
+nouveau_renderbuffer_storage(GLcontext *ctx, struct gl_renderbuffer *rb,
                             GLenum internalFormat,
                             GLuint width, GLuint height)
 {
-       nouveau_renderbuffer_t *nrb = (nouveau_renderbuffer_t *) rb;
+       struct nouveau_surface *s = &to_nouveau_renderbuffer(rb)->surface;
 
-       if (!nouveau_renderbuffer_pixelformat(nrb, internalFormat)) {
-               fprintf(stderr, "%s: unknown internalFormat\n", __func__);
+       if (!set_renderbuffer_format(rb, internalFormat))
                return GL_FALSE;
-       }
-
-       /* If this buffer isn't statically alloc'd, we may need to ask the
-        * drm for more memory */
-       if (rb->Width != width || rb->Height != height) {
-               GLuint pitch;
-
-               /* align pitches to 64 bytes */
-               pitch = ((width * nrb->cpp) + 63) & ~63;
-
-               if (nrb->mem)
-                       nouveau_mem_free(ctx, nrb->mem);
-               nrb->mem = nouveau_mem_alloc(ctx,
-                                            NOUVEAU_MEM_FB |
-                                            NOUVEAU_MEM_MAPPED,
-                                            pitch * height, 0);
-               if (!nrb->mem)
-                       return GL_FALSE;
-
-               /* update nouveau_renderbuffer info */
-               nrb->offset = nouveau_mem_gpu_offset_get(ctx, nrb->mem);
-               nrb->pitch = pitch;
-       }
 
        rb->Width = width;
        rb->Height = height;
-       rb->InternalFormat = internalFormat;
 
-       nouveauSpanSetFunctions(nrb);
+       nouveau_surface_alloc(ctx, s, TILED, NOUVEAU_BO_VRAM | NOUVEAU_BO_MAP,
+                             rb->Format, width, height);
 
+       context_dirty(ctx, FRAMEBUFFER);
        return GL_TRUE;
 }
 
 static void
-nouveau_renderbuffer_delete(struct gl_renderbuffer *rb)
+nouveau_renderbuffer_del(struct gl_renderbuffer *rb)
 {
-       GET_CURRENT_CONTEXT(ctx);
-       nouveau_renderbuffer_t *nrb = (nouveau_renderbuffer_t *) rb;
+       struct nouveau_surface *s = &to_nouveau_renderbuffer(rb)->surface;
 
-       if (nrb->mem)
-               nouveau_mem_free(ctx, nrb->mem);
-       FREE(nrb);
+       nouveau_surface_ref(NULL, s);
+       FREE(rb);
 }
 
-nouveau_renderbuffer_t *
-nouveau_renderbuffer_new(GLenum internalFormat)
+static struct gl_renderbuffer *
+nouveau_renderbuffer_new(GLcontext *ctx, GLuint name)
 {
-       nouveau_renderbuffer_t *nrb;
+       struct gl_renderbuffer *rb;
 
-       nrb = CALLOC_STRUCT(nouveau_renderbuffer);
-       if (!nrb)
+       rb = (struct gl_renderbuffer *)
+               CALLOC_STRUCT(nouveau_renderbuffer);
+       if (!rb)
                return NULL;
 
-       _mesa_init_renderbuffer(&nrb->mesa, 0);
+       _mesa_init_renderbuffer(rb, name);
 
-       if (!nouveau_renderbuffer_pixelformat(nrb, internalFormat)) {
-               fprintf(stderr, "%s: unknown internalFormat\n", __func__);
-               return GL_FALSE;
-       }
+       rb->AllocStorage = nouveau_renderbuffer_storage;
+       rb->Delete = nouveau_renderbuffer_del;
 
-       nrb->mesa.AllocStorage = nouveau_renderbuffer_storage;
-       nrb->mesa.Delete = nouveau_renderbuffer_delete;
-
-       return nrb;
+       return rb;
 }
 
-static void
-nouveau_cliprects_renderbuffer_set(nouveauContextPtr nmesa,
-                                  nouveau_renderbuffer_t * nrb)
+static GLboolean
+nouveau_renderbuffer_dri_storage(GLcontext *ctx, struct gl_renderbuffer *rb,
+                                GLenum internalFormat,
+                                GLuint width, GLuint height)
 {
-       nmesa->numClipRects = 1;
-       nmesa->pClipRects = &nmesa->osClipRect;
-       nmesa->osClipRect.x1 = 0;
-       nmesa->osClipRect.y1 = 0;
-       nmesa->osClipRect.x2 = nrb->mesa.Width;
-       nmesa->osClipRect.y2 = nrb->mesa.Height;
-       nmesa->drawX = 0;
-       nmesa->drawY = 0;
-       nmesa->drawW = nrb->mesa.Width;
-       nmesa->drawH = nrb->mesa.Height;
-}
+       if (!set_renderbuffer_format(rb, internalFormat))
+               return GL_FALSE;
 
-void
-nouveau_window_moved(GLcontext * ctx)
-{
-       nouveauContextPtr nmesa = NOUVEAU_CONTEXT(ctx);
-       nouveau_renderbuffer_t *nrb;
-
-       nrb = (nouveau_renderbuffer_t *) ctx->DrawBuffer->_ColorDrawBuffers[0];
-       if (!nrb)
-               return;
-
-       nouveau_cliprects_renderbuffer_set(nmesa, nrb);
-
-       /* Viewport depends on window size/position, nouveauCalcViewport
-        * will take care of calling the hw-specific WindowMoved
-        */
-       ctx->Driver.Viewport(ctx, ctx->Viewport.X, ctx->Viewport.Y,
-                            ctx->Viewport.Width, ctx->Viewport.Height);
-       /* Scissor depends on window position */
-       ctx->Driver.Scissor(ctx, ctx->Scissor.X, ctx->Scissor.Y,
-                           ctx->Scissor.Width, ctx->Scissor.Height);
+       rb->Width = width;
+       rb->Height = height;
+
+       return GL_TRUE;
 }
 
-GLboolean
-nouveau_build_framebuffer(GLcontext *ctx, struct gl_framebuffer *fb)
+struct gl_renderbuffer *
+nouveau_renderbuffer_dri_new(GLenum format, __DRIdrawable *drawable)
 {
-       nouveauContextPtr nmesa = NOUVEAU_CONTEXT(ctx);
-       nouveau_renderbuffer_t *color[MAX_DRAW_BUFFERS];
-       nouveau_renderbuffer_t *depth;
-
-       _mesa_update_framebuffer(ctx);
-       _mesa_update_draw_buffer_bounds(ctx);
+       struct gl_renderbuffer *rb;
 
-       color[0] = (nouveau_renderbuffer_t *) fb->_ColorDrawBuffers[0];
-       if (fb->_DepthBuffer && fb->_DepthBuffer->Wrapped)
-               depth = (nouveau_renderbuffer_t *) fb->_DepthBuffer->Wrapped;
-       else
-               depth = (nouveau_renderbuffer_t *) fb->_DepthBuffer;
+       rb = nouveau_renderbuffer_new(NULL, 0);
+       if (!rb)
+               return NULL;
 
-       if (!nmesa->hw_func.BindBuffers(nmesa, 1, color, depth))
-               return GL_FALSE;
-       nouveau_window_moved(ctx);
+       rb->AllocStorage = nouveau_renderbuffer_dri_storage;
 
-       return GL_TRUE;
-}
+       if (!set_renderbuffer_format(rb, format)) {
+               nouveau_renderbuffer_del(rb);
+               return NULL;
+       }
 
-static void
-nouveauDrawBuffer(GLcontext *ctx, GLenum buffer)
-{
-       nouveau_build_framebuffer(ctx, ctx->DrawBuffer);
+       return rb;
 }
 
 static struct gl_framebuffer *
-nouveauNewFramebuffer(GLcontext *ctx, GLuint name)
+nouveau_framebuffer_new(GLcontext *ctx, GLuint name)
 {
-       return _mesa_new_framebuffer(ctx, name);
+       struct nouveau_framebuffer *nfb;
+
+       nfb = CALLOC_STRUCT(nouveau_framebuffer);
+       if (!nfb)
+               return NULL;
+
+       _mesa_initialize_user_framebuffer(&nfb->base, name);
+
+       return &nfb->base;
 }
 
-static struct gl_renderbuffer *
-nouveauNewRenderbuffer(GLcontext *ctx, GLuint name)
+struct gl_framebuffer *
+nouveau_framebuffer_dri_new(const GLvisual *visual)
 {
-       nouveau_renderbuffer_t *nrb;
+       struct nouveau_framebuffer *nfb;
 
-       nrb = CALLOC_STRUCT(nouveau_renderbuffer);
-       if (!nrb)
+       nfb = CALLOC_STRUCT(nouveau_framebuffer);
+       if (!nfb)
                return NULL;
 
-       _mesa_init_renderbuffer(&nrb->mesa, name);
+       _mesa_initialize_window_framebuffer(&nfb->base, visual);
 
-       nrb->mesa.AllocStorage = nouveau_renderbuffer_storage;
-       nrb->mesa.Delete = nouveau_renderbuffer_delete;
-       return &nrb->mesa;
+       return &nfb->base;
 }
 
 static void
-nouveauBindFramebuffer(GLcontext *ctx, GLenum target,
-                      struct gl_framebuffer *fb,
-                      struct gl_framebuffer *fbread)
+nouveau_bind_framebuffer(GLcontext *ctx, GLenum target,
+                        struct gl_framebuffer *dfb,
+                        struct gl_framebuffer *rfb)
 {
-       if (target == GL_FRAMEBUFFER_EXT || target == GL_DRAW_FRAMEBUFFER_EXT) {
-               nouveau_build_framebuffer(ctx, fb);
-       }
+       context_dirty(ctx, FRAMEBUFFER);
 }
 
 static void
-nouveauFramebufferRenderbuffer(GLcontext *ctx, struct gl_framebuffer *fb,
-                              GLenum attachment, struct gl_renderbuffer *rb)
+nouveau_framebuffer_renderbuffer(GLcontext *ctx, struct gl_framebuffer *fb,
+                                GLenum attachment, struct gl_renderbuffer *rb)
 {
        _mesa_framebuffer_renderbuffer(ctx, fb, attachment, rb);
-       nouveau_build_framebuffer(ctx, fb);
+
+       context_dirty(ctx, FRAMEBUFFER);
+}
+
+static GLenum
+get_tex_format(struct gl_texture_image *ti)
+{
+       switch (ti->TexFormat) {
+       case MESA_FORMAT_ARGB8888:
+               return GL_RGBA8;
+       case MESA_FORMAT_XRGB8888:
+               return GL_RGB8;
+       case MESA_FORMAT_RGB565:
+               return GL_RGB5;
+       default:
+               assert(0);
+       }
 }
 
 static void
-nouveauRenderTexture(GLcontext * ctx, struct gl_framebuffer *fb,
-                    struct gl_renderbuffer_attachment *att)
+nouveau_render_texture(GLcontext *ctx, struct gl_framebuffer *fb,
+                      struct gl_renderbuffer_attachment *att)
 {
+       struct gl_renderbuffer *rb = att->Renderbuffer;
+       struct gl_texture_image *ti =
+               att->Texture->Image[att->CubeMapFace][att->TextureLevel];
+       int ret;
+
+       /* Allocate a renderbuffer object for the texture if we
+        * haven't already done so. */
+       if (!rb) {
+               rb = nouveau_renderbuffer_new(ctx, ~0);
+               assert(rb);
+
+               rb->AllocStorage = NULL;
+               _mesa_reference_renderbuffer(&att->Renderbuffer, rb);
+       }
+
+       /* Update the renderbuffer fields from the texture. */
+       ret = set_renderbuffer_format(rb, get_tex_format(ti));
+       assert(ret);
+
+       rb->Width = ti->Width;
+       rb->Height = ti->Height;
+       nouveau_surface_ref(&to_nouveau_teximage(ti)->surface,
+                           &to_nouveau_renderbuffer(rb)->surface);
+
+       context_dirty(ctx, FRAMEBUFFER);
 }
 
 static void
-nouveauFinishRenderTexture(GLcontext * ctx,
-                          struct gl_renderbuffer_attachment *att)
+nouveau_finish_render_texture(GLcontext *ctx,
+                             struct gl_renderbuffer_attachment *att)
 {
+       texture_dirty(att->Texture);
 }
 
 void
-nouveauInitBufferFuncs(struct dd_function_table *func)
+nouveau_fbo_functions_init(struct dd_function_table *functions)
 {
-       func->DrawBuffer = nouveauDrawBuffer;
-
-       func->NewFramebuffer = nouveauNewFramebuffer;
-       func->NewRenderbuffer = nouveauNewRenderbuffer;
-       func->BindFramebuffer = nouveauBindFramebuffer;
-       func->FramebufferRenderbuffer = nouveauFramebufferRenderbuffer;
-       func->RenderTexture = nouveauRenderTexture;
-       func->FinishRenderTexture = nouveauFinishRenderTexture;
+       functions->NewFramebuffer = nouveau_framebuffer_new;
+       functions->NewRenderbuffer = nouveau_renderbuffer_new;
+       functions->BindFramebuffer = nouveau_bind_framebuffer;
+       functions->FramebufferRenderbuffer = nouveau_framebuffer_renderbuffer;
+       functions->RenderTexture = nouveau_render_texture;
+       functions->FinishRenderTexture = nouveau_finish_render_texture;
 }
-