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 OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE 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_gldefs.h"
30#include "nv_object.xml.h"
31#include "nv30/nv30-40_3d.xml.h"
32#include "nv30/nv30_context.h"
33#include "nv30/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[0];
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, const struct pipe_scissor_state *scissor_state,
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, NV30_NEW_FRAMEBUFFER, true))
62      return;
63
64   if (scissor_state) {
65      uint32_t minx = scissor_state->minx;
66      uint32_t maxx = MIN2(fb->width, scissor_state->maxx);
67      uint32_t miny = scissor_state->miny;
68      uint32_t maxy = MIN2(fb->height, scissor_state->maxy);
69
70      BEGIN_NV04(push, NV30_3D(SCISSOR_HORIZ), 2);
71      PUSH_DATA (push, minx | (maxx - minx) << 16);
72      PUSH_DATA (push, miny | (maxy - miny) << 16);
73   }
74   else {
75      BEGIN_NV04(push, NV30_3D(SCISSOR_HORIZ), 2);
76      PUSH_DATA (push, 0x10000000);
77      PUSH_DATA (push, 0x10000000);
78   }
79
80   if (buffers & PIPE_CLEAR_COLOR && fb->nr_cbufs) {
81      colr  = pack_rgba(fb->cbufs[0]->format, color->f);
82      mode |= NV30_3D_CLEAR_BUFFERS_COLOR_R |
83              NV30_3D_CLEAR_BUFFERS_COLOR_G |
84              NV30_3D_CLEAR_BUFFERS_COLOR_B |
85              NV30_3D_CLEAR_BUFFERS_COLOR_A;
86   }
87
88   if (fb->zsbuf) {
89      zeta = pack_zeta(fb->zsbuf->format, depth, stencil);
90      if (buffers & PIPE_CLEAR_DEPTH)
91         mode |= NV30_3D_CLEAR_BUFFERS_DEPTH;
92      if (buffers & PIPE_CLEAR_STENCIL) {
93         mode |= NV30_3D_CLEAR_BUFFERS_STENCIL;
94         BEGIN_NV04(push, NV30_3D(STENCIL_ENABLE(0)), 2);
95         PUSH_DATA (push, 0);
96         PUSH_DATA (push, 0x000000ff);
97         nv30->dirty |= NV30_NEW_ZSA;
98      }
99   }
100
101   /*XXX: wtf? fixes clears sometimes not clearing on nv3x... */
102   if (nv30->screen->eng3d->oclass < NV40_3D_CLASS) {
103      BEGIN_NV04(push, NV30_3D(CLEAR_DEPTH_VALUE), 3);
104      PUSH_DATA (push, zeta);
105      PUSH_DATA (push, colr);
106      PUSH_DATA (push, mode);
107   }
108
109   BEGIN_NV04(push, NV30_3D(CLEAR_DEPTH_VALUE), 3);
110   PUSH_DATA (push, zeta);
111   PUSH_DATA (push, colr);
112   PUSH_DATA (push, mode);
113
114   nv30_state_release(nv30);
115
116   /* Make sure regular draw commands will get their scissor state set */
117   nv30->dirty |= NV30_NEW_SCISSOR;
118   nv30->state.scissor_off = 0;
119}
120
121static void
122nv30_clear_render_target(struct pipe_context *pipe, struct pipe_surface *ps,
123                         const union pipe_color_union *color,
124                         unsigned x, unsigned y, unsigned w, unsigned h,
125                         bool render_condition_enabled)
126{
127   struct nv30_context *nv30 = nv30_context(pipe);
128   struct nv30_surface *sf = nv30_surface(ps);
129   struct nv30_miptree *mt = nv30_miptree(ps->texture);
130   struct nouveau_pushbuf *push = nv30->base.pushbuf;
131   struct nouveau_object *eng3d = nv30->screen->eng3d;
132   struct nouveau_pushbuf_refn refn;
133   uint32_t rt_format;
134
135   rt_format = nv30_format(pipe->screen, ps->format)->hw;
136   if (util_format_get_blocksize(ps->format) == 4)
137      rt_format |= NV30_3D_RT_FORMAT_ZETA_Z24S8;
138   else
139      rt_format |= NV30_3D_RT_FORMAT_ZETA_Z16;
140
141   if (nv30_miptree(ps->texture)->swizzled) {
142      rt_format |= NV30_3D_RT_FORMAT_TYPE_SWIZZLED;
143      rt_format |= util_logbase2(sf->width) << 16;
144      rt_format |= util_logbase2(sf->height) << 24;
145   } else {
146      rt_format |= NV30_3D_RT_FORMAT_TYPE_LINEAR;
147   }
148
149   refn.bo = mt->base.bo;
150   refn.flags = NOUVEAU_BO_VRAM | NOUVEAU_BO_WR;
151   if (nouveau_pushbuf_space(push, 32, 1, 0) ||
152       nouveau_pushbuf_refn (push, &refn, 1))
153      return;
154
155   BEGIN_NV04(push, NV30_3D(RT_ENABLE), 1);
156   PUSH_DATA (push, NV30_3D_RT_ENABLE_COLOR0);
157   BEGIN_NV04(push, NV30_3D(RT_HORIZ), 3);
158   PUSH_DATA (push, sf->width << 16);
159   PUSH_DATA (push, sf->height << 16);
160   PUSH_DATA (push, rt_format);
161   BEGIN_NV04(push, NV30_3D(COLOR0_PITCH), 2);
162   if (eng3d->oclass < NV40_3D_CLASS)
163      PUSH_DATA (push, (sf->pitch << 16) | sf->pitch);
164   else
165      PUSH_DATA (push, sf->pitch);
166   PUSH_RELOC(push, mt->base.bo, sf->offset, NOUVEAU_BO_LOW, 0, 0);
167   BEGIN_NV04(push, NV30_3D(SCISSOR_HORIZ), 2);
168   PUSH_DATA (push, (w << 16) | x);
169   PUSH_DATA (push, (h << 16) | y);
170
171   BEGIN_NV04(push, NV30_3D(CLEAR_COLOR_VALUE), 2);
172   PUSH_DATA (push, pack_rgba(ps->format, color->f));
173   PUSH_DATA (push, NV30_3D_CLEAR_BUFFERS_COLOR_R |
174                    NV30_3D_CLEAR_BUFFERS_COLOR_G |
175                    NV30_3D_CLEAR_BUFFERS_COLOR_B |
176                    NV30_3D_CLEAR_BUFFERS_COLOR_A);
177
178   nv30->dirty |= NV30_NEW_FRAMEBUFFER | NV30_NEW_SCISSOR;
179   nv30->state.scissor_off = 0;
180}
181
182static void
183nv30_clear_depth_stencil(struct pipe_context *pipe, struct pipe_surface *ps,
184                         unsigned buffers, double depth, unsigned stencil,
185                         unsigned x, unsigned y, unsigned w, unsigned h,
186                         bool render_condition_enabled)
187{
188   struct nv30_context *nv30 = nv30_context(pipe);
189   struct nv30_surface *sf = nv30_surface(ps);
190   struct nv30_miptree *mt = nv30_miptree(ps->texture);
191   struct nouveau_pushbuf *push = nv30->base.pushbuf;
192   struct nouveau_object *eng3d = nv30->screen->eng3d;
193   struct nouveau_pushbuf_refn refn;
194   uint32_t rt_format, mode = 0;
195
196   rt_format = nv30_format(pipe->screen, ps->format)->hw;
197   if (util_format_get_blocksize(ps->format) == 4)
198      rt_format |= NV30_3D_RT_FORMAT_COLOR_A8R8G8B8;
199   else
200      rt_format |= NV30_3D_RT_FORMAT_COLOR_R5G6B5;
201
202   if (nv30_miptree(ps->texture)->swizzled) {
203      rt_format |= NV30_3D_RT_FORMAT_TYPE_SWIZZLED;
204      rt_format |= util_logbase2(sf->width) << 16;
205      rt_format |= util_logbase2(sf->height) << 24;
206   } else {
207      rt_format |= NV30_3D_RT_FORMAT_TYPE_LINEAR;
208   }
209
210   if (buffers & PIPE_CLEAR_DEPTH)
211      mode |= NV30_3D_CLEAR_BUFFERS_DEPTH;
212   if (buffers & PIPE_CLEAR_STENCIL)
213      mode |= NV30_3D_CLEAR_BUFFERS_STENCIL;
214
215   refn.bo = mt->base.bo;
216   refn.flags = NOUVEAU_BO_VRAM | NOUVEAU_BO_WR;
217   if (nouveau_pushbuf_space(push, 32, 1, 0) ||
218       nouveau_pushbuf_refn (push, &refn, 1))
219      return;
220
221   BEGIN_NV04(push, NV30_3D(RT_ENABLE), 1);
222   PUSH_DATA (push, 0);
223   BEGIN_NV04(push, NV30_3D(RT_HORIZ), 3);
224   PUSH_DATA (push, sf->width << 16);
225   PUSH_DATA (push, sf->height << 16);
226   PUSH_DATA (push, rt_format);
227   if (eng3d->oclass < NV40_3D_CLASS) {
228      BEGIN_NV04(push, NV30_3D(COLOR0_PITCH), 1);
229      PUSH_DATA (push, (sf->pitch << 16) | sf->pitch);
230   } else {
231      BEGIN_NV04(push, NV40_3D(ZETA_PITCH), 1);
232      PUSH_DATA (push, sf->pitch);
233   }
234   BEGIN_NV04(push, NV30_3D(ZETA_OFFSET), 1);
235   PUSH_RELOC(push, mt->base.bo, sf->offset, NOUVEAU_BO_LOW, 0, 0);
236   BEGIN_NV04(push, NV30_3D(SCISSOR_HORIZ), 2);
237   PUSH_DATA (push, (w << 16) | x);
238   PUSH_DATA (push, (h << 16) | y);
239
240   BEGIN_NV04(push, NV30_3D(CLEAR_DEPTH_VALUE), 1);
241   PUSH_DATA (push, pack_zeta(ps->format, depth, stencil));
242   BEGIN_NV04(push, NV30_3D(CLEAR_BUFFERS), 1);
243   PUSH_DATA (push, mode);
244
245   nv30->dirty |= NV30_NEW_FRAMEBUFFER | NV30_NEW_SCISSOR;
246   nv30->state.scissor_off = 0;
247}
248
249void
250nv30_clear_init(struct pipe_context *pipe)
251{
252   pipe->clear = nv30_clear;
253   pipe->clear_render_target = nv30_clear_render_target;
254   pipe->clear_depth_stencil = nv30_clear_depth_stencil;
255}
256