r600g: use CP DMA for buffer clears on evergreen+
[mesa.git] / src / gallium / drivers / nv30 / nv30_clear.c
index 8c3ca204d586912aa2ce86735a00bdcd6186e0b0..8992de31d09508508b81c35ab1821d0ae67663f6 100644 (file)
-#include "pipe/p_context.h"
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * 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 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 AUTHORS OR COPYRIGHT HOLDERS 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.
+ *
+ * Authors: Ben Skeggs
+ *
+ */
+
 #include "pipe/p_defines.h"
-#include "pipe/p_state.h"
+#include "util/u_pack_color.h"
 
+#include "nouveau/nouveau_gldefs.h"
+#include "nouveau/nv_object.xml.h"
+#include "nv30-40_3d.xml.h"
 #include "nv30_context.h"
+#include "nv30_format.h"
+
+static INLINE uint32_t
+pack_rgba(enum pipe_format format, const float *rgba)
+{
+   union util_color uc;
+   util_pack_color(rgba, format, &uc);
+   return uc.ui;
+}
+
+static INLINE uint32_t
+pack_zeta(enum pipe_format format, double depth, unsigned stencil)
+{
+   uint32_t zuint = (uint32_t)(depth * 4294967295.0);
+   if (format != PIPE_FORMAT_Z16_UNORM)
+      return (zuint & 0xffffff00) | (stencil & 0xff);
+   return zuint >> 16;
+}
+
+static void
+nv30_clear(struct pipe_context *pipe, unsigned buffers,
+           const union pipe_color_union *color, double depth, unsigned stencil)
+{
+   struct nv30_context *nv30 = nv30_context(pipe);
+   struct nouveau_pushbuf *push = nv30->base.pushbuf;
+   struct pipe_framebuffer_state *fb = &nv30->framebuffer;
+   uint32_t colr = 0, zeta = 0, mode = 0;
+
+   if (!nv30_state_validate(nv30, TRUE))
+      return;
+
+   if (buffers & PIPE_CLEAR_COLOR && fb->nr_cbufs) {
+      colr  = pack_rgba(fb->cbufs[0]->format, color->f);
+      mode |= NV30_3D_CLEAR_BUFFERS_COLOR_R |
+              NV30_3D_CLEAR_BUFFERS_COLOR_G |
+              NV30_3D_CLEAR_BUFFERS_COLOR_B |
+              NV30_3D_CLEAR_BUFFERS_COLOR_A;
+   }
+
+   if (fb->zsbuf) {
+      zeta = pack_zeta(fb->zsbuf->format, depth, stencil);
+      if (buffers & PIPE_CLEAR_DEPTH)
+         mode |= NV30_3D_CLEAR_BUFFERS_DEPTH;
+      if (buffers & PIPE_CLEAR_STENCIL)
+         mode |= NV30_3D_CLEAR_BUFFERS_STENCIL;
+   }
+
+   /*XXX: wtf? fixes clears sometimes not clearing on nv3x... */
+   if (nv30->screen->eng3d->oclass < NV40_3D_CLASS) {
+      BEGIN_NV04(push, NV30_3D(CLEAR_DEPTH_VALUE), 3);
+      PUSH_DATA (push, zeta);
+      PUSH_DATA (push, colr);
+      PUSH_DATA (push, mode);
+   }
+
+   BEGIN_NV04(push, NV30_3D(CLEAR_DEPTH_VALUE), 3);
+   PUSH_DATA (push, zeta);
+   PUSH_DATA (push, colr);
+   PUSH_DATA (push, mode);
+
+   nv30_state_release(nv30);
+}
+
+static void
+nv30_clear_render_target(struct pipe_context *pipe, struct pipe_surface *ps,
+                         const union pipe_color_union *color,
+                         unsigned x, unsigned y, unsigned w, unsigned h)
+{
+   struct nv30_context *nv30 = nv30_context(pipe);
+   struct nv30_surface *sf = nv30_surface(ps);
+   struct nv30_miptree *mt = nv30_miptree(ps->texture);
+   struct nouveau_pushbuf *push = nv30->base.pushbuf;
+   struct nouveau_object *eng3d = nv30->screen->eng3d;
+   struct nouveau_pushbuf_refn refn;
+   uint32_t rt_format;
+
+   rt_format = nv30_format(pipe->screen, ps->format)->hw;
+   if (util_format_get_blocksize(ps->format) == 4)
+      rt_format |= NV30_3D_RT_FORMAT_ZETA_Z24S8;
+   else
+      rt_format |= NV30_3D_RT_FORMAT_ZETA_Z16;
+
+   if (nv30_miptree(ps->texture)->swizzled) {
+      rt_format |= NV30_3D_RT_FORMAT_TYPE_SWIZZLED;
+      rt_format |= util_logbase2(sf->width) << 16;
+      rt_format |= util_logbase2(sf->height) << 24;
+   } else {
+      rt_format |= NV30_3D_RT_FORMAT_TYPE_LINEAR;
+   }
+
+   refn.bo = mt->base.bo;
+   refn.flags = NOUVEAU_BO_VRAM | NOUVEAU_BO_WR;
+   if (nouveau_pushbuf_space(push, 16, 1, 0) ||
+       nouveau_pushbuf_refn (push, &refn, 1))
+      return;
+
+   BEGIN_NV04(push, NV30_3D(RT_ENABLE), 1);
+   PUSH_DATA (push, NV30_3D_RT_ENABLE_COLOR0);
+   BEGIN_NV04(push, NV30_3D(RT_HORIZ), 3);
+   PUSH_DATA (push, sf->width << 16);
+   PUSH_DATA (push, sf->height << 16);
+   PUSH_DATA (push, rt_format);
+   BEGIN_NV04(push, NV30_3D(COLOR0_PITCH), 2);
+   if (eng3d->oclass < NV40_3D_CLASS)
+      PUSH_DATA (push, (sf->pitch << 16) | sf->pitch);
+   else
+      PUSH_DATA (push, sf->pitch);
+   PUSH_RELOC(push, mt->base.bo, sf->offset, NOUVEAU_BO_LOW, 0, 0);
+   BEGIN_NV04(push, NV30_3D(SCISSOR_HORIZ), 2);
+   PUSH_DATA (push, (w << 16) | x);
+   PUSH_DATA (push, (h << 16) | y);
+
+   BEGIN_NV04(push, NV30_3D(CLEAR_COLOR_VALUE), 2);
+   PUSH_DATA (push, pack_rgba(ps->format, color->f));
+   PUSH_DATA (push, NV30_3D_CLEAR_BUFFERS_COLOR_R |
+                    NV30_3D_CLEAR_BUFFERS_COLOR_G |
+                    NV30_3D_CLEAR_BUFFERS_COLOR_B |
+                    NV30_3D_CLEAR_BUFFERS_COLOR_A);
+
+   nv30->dirty |= NV30_NEW_FRAMEBUFFER | NV30_NEW_SCISSOR;
+}
+
+static void
+nv30_clear_depth_stencil(struct pipe_context *pipe, struct pipe_surface *ps,
+                         unsigned buffers, double depth, unsigned stencil,
+                         unsigned x, unsigned y, unsigned w, unsigned h)
+{
+   struct nv30_context *nv30 = nv30_context(pipe);
+   struct nv30_surface *sf = nv30_surface(ps);
+   struct nv30_miptree *mt = nv30_miptree(ps->texture);
+   struct nouveau_pushbuf *push = nv30->base.pushbuf;
+   struct nouveau_object *eng3d = nv30->screen->eng3d;
+   struct nouveau_pushbuf_refn refn;
+   uint32_t rt_format, mode = 0;
+
+   rt_format = nv30_format(pipe->screen, ps->format)->hw;
+   if (util_format_get_blocksize(ps->format) == 4)
+      rt_format |= NV30_3D_RT_FORMAT_COLOR_A8R8G8B8;
+   else
+      rt_format |= NV30_3D_RT_FORMAT_COLOR_R5G6B5;
+
+   if (nv30_miptree(ps->texture)->swizzled) {
+      rt_format |= NV30_3D_RT_FORMAT_TYPE_SWIZZLED;
+      rt_format |= util_logbase2(sf->width) << 16;
+      rt_format |= util_logbase2(sf->height) << 24;
+   } else {
+      rt_format |= NV30_3D_RT_FORMAT_TYPE_LINEAR;
+   }
+
+   if (buffers & PIPE_CLEAR_DEPTH)
+      mode |= NV30_3D_CLEAR_BUFFERS_DEPTH;
+   if (buffers & PIPE_CLEAR_STENCIL)
+      mode |= NV30_3D_CLEAR_BUFFERS_STENCIL;
+
+   refn.bo = mt->base.bo;
+   refn.flags = NOUVEAU_BO_VRAM | NOUVEAU_BO_WR;
+   if (nouveau_pushbuf_space(push, 32, 1, 0) ||
+       nouveau_pushbuf_refn (push, &refn, 1))
+      return;
+
+   BEGIN_NV04(push, NV30_3D(RT_ENABLE), 1);
+   PUSH_DATA (push, 0);
+   BEGIN_NV04(push, NV30_3D(RT_HORIZ), 3);
+   PUSH_DATA (push, sf->width << 16);
+   PUSH_DATA (push, sf->height << 16);
+   PUSH_DATA (push, rt_format);
+   if (eng3d->oclass < NV40_3D_CLASS) {
+      BEGIN_NV04(push, NV30_3D(COLOR0_PITCH), 1);
+      PUSH_DATA (push, (sf->pitch << 16) | sf->pitch);
+   } else {
+      BEGIN_NV04(push, NV40_3D(ZETA_PITCH), 1);
+      PUSH_DATA (push, sf->pitch);
+   }
+   BEGIN_NV04(push, NV30_3D(ZETA_OFFSET), 1);
+   PUSH_RELOC(push, mt->base.bo, sf->offset, NOUVEAU_BO_LOW, 0, 0);
+   BEGIN_NV04(push, NV30_3D(SCISSOR_HORIZ), 2);
+   PUSH_DATA (push, (w << 16) | x);
+   PUSH_DATA (push, (h << 16) | y);
+
+   BEGIN_NV04(push, NV30_3D(CLEAR_DEPTH_VALUE), 1);
+   PUSH_DATA (push, pack_zeta(ps->format, depth, stencil));
+   BEGIN_NV04(push, NV30_3D(CLEAR_BUFFERS), 1);
+   PUSH_DATA (push, mode);
+
+   nv30->dirty |= NV30_NEW_FRAMEBUFFER | NV30_NEW_SCISSOR;
+}
 
 void
-nv30_clear(struct pipe_context *pipe, struct pipe_surface *ps,
-          unsigned clearValue)
+nv30_clear_init(struct pipe_context *pipe)
 {
-       pipe->surface_fill(pipe, ps, 0, 0, ps->width, ps->height, clearValue);
-       ps->status = PIPE_SURFACE_STATUS_CLEAR;
+   pipe->clear = nv30_clear;
+   pipe->clear_render_target = nv30_clear_render_target;
+   pipe->clear_depth_stencil = nv30_clear_depth_stencil;
 }