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 | NV30_NEW_SCISSOR, 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         BEGIN_NV04(push, NV30_3D(STENCIL_ENABLE(0)), 2);
79         PUSH_DATA (push, 0);
80         PUSH_DATA (push, 0x000000ff);
81         nv30->dirty |= NV30_NEW_ZSA;
82      }
83   }
84
85   /*XXX: wtf? fixes clears sometimes not clearing on nv3x... */
86   if (nv30->screen->eng3d->oclass < NV40_3D_CLASS) {
87      BEGIN_NV04(push, NV30_3D(CLEAR_DEPTH_VALUE), 3);
88      PUSH_DATA (push, zeta);
89      PUSH_DATA (push, colr);
90      PUSH_DATA (push, mode);
91   }
92
93   BEGIN_NV04(push, NV30_3D(CLEAR_DEPTH_VALUE), 3);
94   PUSH_DATA (push, zeta);
95   PUSH_DATA (push, colr);
96   PUSH_DATA (push, mode);
97
98   nv30_state_release(nv30);
99}
100
101static void
102nv30_clear_render_target(struct pipe_context *pipe, struct pipe_surface *ps,
103                         const union pipe_color_union *color,
104                         unsigned x, unsigned y, unsigned w, unsigned h,
105                         bool render_condition_enabled)
106{
107   struct nv30_context *nv30 = nv30_context(pipe);
108   struct nv30_surface *sf = nv30_surface(ps);
109   struct nv30_miptree *mt = nv30_miptree(ps->texture);
110   struct nouveau_pushbuf *push = nv30->base.pushbuf;
111   struct nouveau_object *eng3d = nv30->screen->eng3d;
112   struct nouveau_pushbuf_refn refn;
113   uint32_t rt_format;
114
115   rt_format = nv30_format(pipe->screen, ps->format)->hw;
116   if (util_format_get_blocksize(ps->format) == 4)
117      rt_format |= NV30_3D_RT_FORMAT_ZETA_Z24S8;
118   else
119      rt_format |= NV30_3D_RT_FORMAT_ZETA_Z16;
120
121   if (nv30_miptree(ps->texture)->swizzled) {
122      rt_format |= NV30_3D_RT_FORMAT_TYPE_SWIZZLED;
123      rt_format |= util_logbase2(sf->width) << 16;
124      rt_format |= util_logbase2(sf->height) << 24;
125   } else {
126      rt_format |= NV30_3D_RT_FORMAT_TYPE_LINEAR;
127   }
128
129   refn.bo = mt->base.bo;
130   refn.flags = NOUVEAU_BO_VRAM | NOUVEAU_BO_WR;
131   if (nouveau_pushbuf_space(push, 32, 1, 0) ||
132       nouveau_pushbuf_refn (push, &refn, 1))
133      return;
134
135   BEGIN_NV04(push, NV30_3D(RT_ENABLE), 1);
136   PUSH_DATA (push, NV30_3D_RT_ENABLE_COLOR0);
137   BEGIN_NV04(push, NV30_3D(RT_HORIZ), 3);
138   PUSH_DATA (push, sf->width << 16);
139   PUSH_DATA (push, sf->height << 16);
140   PUSH_DATA (push, rt_format);
141   BEGIN_NV04(push, NV30_3D(COLOR0_PITCH), 2);
142   if (eng3d->oclass < NV40_3D_CLASS)
143      PUSH_DATA (push, (sf->pitch << 16) | sf->pitch);
144   else
145      PUSH_DATA (push, sf->pitch);
146   PUSH_RELOC(push, mt->base.bo, sf->offset, NOUVEAU_BO_LOW, 0, 0);
147   BEGIN_NV04(push, NV30_3D(SCISSOR_HORIZ), 2);
148   PUSH_DATA (push, (w << 16) | x);
149   PUSH_DATA (push, (h << 16) | y);
150
151   BEGIN_NV04(push, NV30_3D(CLEAR_COLOR_VALUE), 2);
152   PUSH_DATA (push, pack_rgba(ps->format, color->f));
153   PUSH_DATA (push, NV30_3D_CLEAR_BUFFERS_COLOR_R |
154                    NV30_3D_CLEAR_BUFFERS_COLOR_G |
155                    NV30_3D_CLEAR_BUFFERS_COLOR_B |
156                    NV30_3D_CLEAR_BUFFERS_COLOR_A);
157
158   nv30->dirty |= NV30_NEW_FRAMEBUFFER | NV30_NEW_SCISSOR;
159}
160
161static void
162nv30_clear_depth_stencil(struct pipe_context *pipe, struct pipe_surface *ps,
163                         unsigned buffers, double depth, unsigned stencil,
164                         unsigned x, unsigned y, unsigned w, unsigned h,
165                         bool render_condition_enabled)
166{
167   struct nv30_context *nv30 = nv30_context(pipe);
168   struct nv30_surface *sf = nv30_surface(ps);
169   struct nv30_miptree *mt = nv30_miptree(ps->texture);
170   struct nouveau_pushbuf *push = nv30->base.pushbuf;
171   struct nouveau_object *eng3d = nv30->screen->eng3d;
172   struct nouveau_pushbuf_refn refn;
173   uint32_t rt_format, mode = 0;
174
175   rt_format = nv30_format(pipe->screen, ps->format)->hw;
176   if (util_format_get_blocksize(ps->format) == 4)
177      rt_format |= NV30_3D_RT_FORMAT_COLOR_A8R8G8B8;
178   else
179      rt_format |= NV30_3D_RT_FORMAT_COLOR_R5G6B5;
180
181   if (nv30_miptree(ps->texture)->swizzled) {
182      rt_format |= NV30_3D_RT_FORMAT_TYPE_SWIZZLED;
183      rt_format |= util_logbase2(sf->width) << 16;
184      rt_format |= util_logbase2(sf->height) << 24;
185   } else {
186      rt_format |= NV30_3D_RT_FORMAT_TYPE_LINEAR;
187   }
188
189   if (buffers & PIPE_CLEAR_DEPTH)
190      mode |= NV30_3D_CLEAR_BUFFERS_DEPTH;
191   if (buffers & PIPE_CLEAR_STENCIL)
192      mode |= NV30_3D_CLEAR_BUFFERS_STENCIL;
193
194   refn.bo = mt->base.bo;
195   refn.flags = NOUVEAU_BO_VRAM | NOUVEAU_BO_WR;
196   if (nouveau_pushbuf_space(push, 32, 1, 0) ||
197       nouveau_pushbuf_refn (push, &refn, 1))
198      return;
199
200   BEGIN_NV04(push, NV30_3D(RT_ENABLE), 1);
201   PUSH_DATA (push, 0);
202   BEGIN_NV04(push, NV30_3D(RT_HORIZ), 3);
203   PUSH_DATA (push, sf->width << 16);
204   PUSH_DATA (push, sf->height << 16);
205   PUSH_DATA (push, rt_format);
206   if (eng3d->oclass < NV40_3D_CLASS) {
207      BEGIN_NV04(push, NV30_3D(COLOR0_PITCH), 1);
208      PUSH_DATA (push, (sf->pitch << 16) | sf->pitch);
209   } else {
210      BEGIN_NV04(push, NV40_3D(ZETA_PITCH), 1);
211      PUSH_DATA (push, sf->pitch);
212   }
213   BEGIN_NV04(push, NV30_3D(ZETA_OFFSET), 1);
214   PUSH_RELOC(push, mt->base.bo, sf->offset, NOUVEAU_BO_LOW, 0, 0);
215   BEGIN_NV04(push, NV30_3D(SCISSOR_HORIZ), 2);
216   PUSH_DATA (push, (w << 16) | x);
217   PUSH_DATA (push, (h << 16) | y);
218
219   BEGIN_NV04(push, NV30_3D(CLEAR_DEPTH_VALUE), 1);
220   PUSH_DATA (push, pack_zeta(ps->format, depth, stencil));
221   BEGIN_NV04(push, NV30_3D(CLEAR_BUFFERS), 1);
222   PUSH_DATA (push, mode);
223
224   nv30->dirty |= NV30_NEW_FRAMEBUFFER | NV30_NEW_SCISSOR;
225}
226
227void
228nv30_clear_init(struct pipe_context *pipe)
229{
230   pipe->clear = nv30_clear;
231   pipe->clear_render_target = nv30_clear_render_target;
232   pipe->clear_depth_stencil = nv30_clear_depth_stencil;
233}
234