1/*
2 * Copyright 2012 Red Hat Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
19 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 * SOFTWARE.
21 *
22 * Authors: Ben Skeggs
23 *
24 */
25
26#include "pipe/p_defines.h"
27#include "util/u_pack_color.h"
28
29#include "nouveau/nouveau_gldefs.h"
30#include "nouveau/nv_object.xml.h"
31#include "nv30-40_3d.xml.h"
32#include "nv30_context.h"
33#include "nv30_format.h"
34
35static INLINE uint32_t
36pack_rgba(enum pipe_format format, const float *rgba)
37{
38   union util_color uc;
39   util_pack_color(rgba, format, &uc);
40   return uc.ui;
41}
42
43static INLINE uint32_t
44pack_zeta(enum pipe_format format, double depth, unsigned stencil)
45{
46   uint32_t zuint = (uint32_t)(depth * 4294967295.0);
47   if (format != PIPE_FORMAT_Z16_UNORM)
48      return (zuint & 0xffffff00) | (stencil & 0xff);
49   return zuint >> 16;
50}
51
52static void
53nv30_clear(struct pipe_context *pipe, unsigned buffers,
54           const union pipe_color_union *color, double depth, unsigned stencil)
55{
56   struct nv30_context *nv30 = nv30_context(pipe);
57   struct nouveau_pushbuf *push = nv30->base.pushbuf;
58   struct pipe_framebuffer_state *fb = &nv30->framebuffer;
59   uint32_t colr = 0, zeta = 0, mode = 0;
60
61   if (!nv30_state_validate(nv30, TRUE))
62      return;
63
64   if (buffers & PIPE_CLEAR_COLOR && fb->nr_cbufs) {
65      colr  = pack_rgba(fb->cbufs[0]->format, color->f);
66      mode |= NV30_3D_CLEAR_BUFFERS_COLOR_R |
67              NV30_3D_CLEAR_BUFFERS_COLOR_G |
68              NV30_3D_CLEAR_BUFFERS_COLOR_B |
69              NV30_3D_CLEAR_BUFFERS_COLOR_A;
70   }
71
72   if (fb->zsbuf) {
73      zeta = pack_zeta(fb->zsbuf->format, depth, stencil);
74      if (buffers & PIPE_CLEAR_DEPTH)
75         mode |= NV30_3D_CLEAR_BUFFERS_DEPTH;
76      if (buffers & PIPE_CLEAR_STENCIL)
77         mode |= NV30_3D_CLEAR_BUFFERS_STENCIL;
78   }
79
80   /*XXX: wtf? fixes clears sometimes not clearing on nv3x... */
81   if (nv30->screen->eng3d->oclass < NV40_3D_CLASS) {
82      BEGIN_NV04(push, NV30_3D(CLEAR_DEPTH_VALUE), 3);
83      PUSH_DATA (push, zeta);
84      PUSH_DATA (push, colr);
85      PUSH_DATA (push, mode);
86   }
87
88   BEGIN_NV04(push, NV30_3D(CLEAR_DEPTH_VALUE), 3);
89   PUSH_DATA (push, zeta);
90   PUSH_DATA (push, colr);
91   PUSH_DATA (push, mode);
92
93   nv30_state_release(nv30);
94}
95
96static void
97nv30_clear_render_target(struct pipe_context *pipe, struct pipe_surface *ps,
98                         const union pipe_color_union *color,
99                         unsigned x, unsigned y, unsigned w, unsigned h)
100{
101   struct nv30_context *nv30 = nv30_context(pipe);
102   struct nv30_surface *sf = nv30_surface(ps);
103   struct nv30_miptree *mt = nv30_miptree(ps->texture);
104   struct nouveau_pushbuf *push = nv30->base.pushbuf;
105   struct nouveau_object *eng3d = nv30->screen->eng3d;
106   struct nouveau_pushbuf_refn refn;
107   uint32_t rt_format;
108
109   rt_format = nv30_format(pipe->screen, ps->format)->hw;
110   if (util_format_get_blocksize(ps->format) == 4)
111      rt_format |= NV30_3D_RT_FORMAT_ZETA_Z24S8;
112   else
113      rt_format |= NV30_3D_RT_FORMAT_ZETA_Z16;
114
115   if (nv30_miptree(ps->texture)->swizzled) {
116      rt_format |= NV30_3D_RT_FORMAT_TYPE_SWIZZLED;
117      rt_format |= util_logbase2(sf->width) << 16;
118      rt_format |= util_logbase2(sf->height) << 24;
119   } else {
120      rt_format |= NV30_3D_RT_FORMAT_TYPE_LINEAR;
121   }
122
123   refn.bo = mt->base.bo;
124   refn.flags = NOUVEAU_BO_VRAM | NOUVEAU_BO_WR;
125   if (nouveau_pushbuf_space(push, 16, 1, 0) ||
126       nouveau_pushbuf_refn (push, &refn, 1))
127      return;
128
129   BEGIN_NV04(push, NV30_3D(RT_ENABLE), 1);
130   PUSH_DATA (push, NV30_3D_RT_ENABLE_COLOR0);
131   BEGIN_NV04(push, NV30_3D(RT_HORIZ), 3);
132   PUSH_DATA (push, sf->width << 16);
133   PUSH_DATA (push, sf->height << 16);
134   PUSH_DATA (push, rt_format);
135   BEGIN_NV04(push, NV30_3D(COLOR0_PITCH), 2);
136   if (eng3d->oclass < NV40_3D_CLASS)
137      PUSH_DATA (push, (sf->pitch << 16) | sf->pitch);
138   else
139      PUSH_DATA (push, sf->pitch);
140   PUSH_RELOC(push, mt->base.bo, sf->offset, NOUVEAU_BO_LOW, 0, 0);
141   BEGIN_NV04(push, NV30_3D(SCISSOR_HORIZ), 2);
142   PUSH_DATA (push, (w << 16) | x);
143   PUSH_DATA (push, (h << 16) | y);
144
145   BEGIN_NV04(push, NV30_3D(CLEAR_COLOR_VALUE), 2);
146   PUSH_DATA (push, pack_rgba(ps->format, color->f));
147   PUSH_DATA (push, NV30_3D_CLEAR_BUFFERS_COLOR_R |
148                    NV30_3D_CLEAR_BUFFERS_COLOR_G |
149                    NV30_3D_CLEAR_BUFFERS_COLOR_B |
150                    NV30_3D_CLEAR_BUFFERS_COLOR_A);
151
152   nv30->dirty |= NV30_NEW_FRAMEBUFFER | NV30_NEW_SCISSOR;
153}
154
155static void
156nv30_clear_depth_stencil(struct pipe_context *pipe, struct pipe_surface *ps,
157                         unsigned buffers, double depth, unsigned stencil,
158                         unsigned x, unsigned y, unsigned w, unsigned h)
159{
160   struct nv30_context *nv30 = nv30_context(pipe);
161   struct nv30_surface *sf = nv30_surface(ps);
162   struct nv30_miptree *mt = nv30_miptree(ps->texture);
163   struct nouveau_pushbuf *push = nv30->base.pushbuf;
164   struct nouveau_object *eng3d = nv30->screen->eng3d;
165   struct nouveau_pushbuf_refn refn;
166   uint32_t rt_format, mode = 0;
167
168   rt_format = nv30_format(pipe->screen, ps->format)->hw;
169   if (util_format_get_blocksize(ps->format) == 4)
170      rt_format |= NV30_3D_RT_FORMAT_COLOR_A8R8G8B8;
171   else
172      rt_format |= NV30_3D_RT_FORMAT_COLOR_R5G6B5;
173
174   if (nv30_miptree(ps->texture)->swizzled) {
175      rt_format |= NV30_3D_RT_FORMAT_TYPE_SWIZZLED;
176      rt_format |= util_logbase2(sf->width) << 16;
177      rt_format |= util_logbase2(sf->height) << 24;
178   } else {
179      rt_format |= NV30_3D_RT_FORMAT_TYPE_LINEAR;
180   }
181
182   if (buffers & PIPE_CLEAR_DEPTH)
183      mode |= NV30_3D_CLEAR_BUFFERS_DEPTH;
184   if (buffers & PIPE_CLEAR_STENCIL)
185      mode |= NV30_3D_CLEAR_BUFFERS_STENCIL;
186
187   refn.bo = mt->base.bo;
188   refn.flags = NOUVEAU_BO_VRAM | NOUVEAU_BO_WR;
189   if (nouveau_pushbuf_space(push, 32, 1, 0) ||
190       nouveau_pushbuf_refn (push, &refn, 1))
191      return;
192
193   BEGIN_NV04(push, NV30_3D(RT_ENABLE), 1);
194   PUSH_DATA (push, 0);
195   BEGIN_NV04(push, NV30_3D(RT_HORIZ), 3);
196   PUSH_DATA (push, sf->width << 16);
197   PUSH_DATA (push, sf->height << 16);
198   PUSH_DATA (push, rt_format);
199   if (eng3d->oclass < NV40_3D_CLASS) {
200      BEGIN_NV04(push, NV30_3D(COLOR0_PITCH), 1);
201      PUSH_DATA (push, (sf->pitch << 16) | sf->pitch);
202   } else {
203      BEGIN_NV04(push, NV40_3D(ZETA_PITCH), 1);
204      PUSH_DATA (push, sf->pitch);
205   }
206   BEGIN_NV04(push, NV30_3D(ZETA_OFFSET), 1);
207   PUSH_RELOC(push, mt->base.bo, sf->offset, NOUVEAU_BO_LOW, 0, 0);
208   BEGIN_NV04(push, NV30_3D(SCISSOR_HORIZ), 2);
209   PUSH_DATA (push, (w << 16) | x);
210   PUSH_DATA (push, (h << 16) | y);
211
212   BEGIN_NV04(push, NV30_3D(CLEAR_DEPTH_VALUE), 1);
213   PUSH_DATA (push, pack_zeta(ps->format, depth, stencil));
214   BEGIN_NV04(push, NV30_3D(CLEAR_BUFFERS), 1);
215   PUSH_DATA (push, mode);
216
217   nv30->dirty |= NV30_NEW_FRAMEBUFFER | NV30_NEW_SCISSOR;
218}
219
220void
221nv30_clear_init(struct pipe_context *pipe)
222{
223   pipe->clear = nv30_clear;
224   pipe->clear_render_target = nv30_clear_render_target;
225   pipe->clear_depth_stencil = nv30_clear_depth_stencil;
226}
227