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 "util/u_format.h"
27#include "util/u_math.h"
28#include "util/u_half.h"
29
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 void
36nv30_validate_fb(struct nv30_context *nv30)
37{
38   struct pipe_screen *pscreen = &nv30->screen->base.base;
39   struct pipe_framebuffer_state *fb = &nv30->framebuffer;
40   struct nouveau_pushbuf *push = nv30->base.pushbuf;
41   struct nouveau_object *eng3d = nv30->screen->eng3d;
42   uint32_t rt_format;
43   int h = fb->height;
44   int w = fb->width;
45   int x = 0;
46   int y = 0;
47
48   nv30->state.rt_enable = (NV30_3D_RT_ENABLE_COLOR0 << fb->nr_cbufs) - 1;
49   if (nv30->state.rt_enable > 1)
50      nv30->state.rt_enable |= NV30_3D_RT_ENABLE_MRT;
51
52   rt_format = 0;
53   if (fb->nr_cbufs > 0) {
54      struct nv30_miptree *mt = nv30_miptree(fb->cbufs[0]->texture);
55      rt_format |= nv30_format(pscreen, fb->cbufs[0]->format)->hw;
56      rt_format |= mt->ms_mode;
57      if (mt->swizzled)
58         rt_format |= NV30_3D_RT_FORMAT_TYPE_SWIZZLED;
59      else
60         rt_format |= NV30_3D_RT_FORMAT_TYPE_LINEAR;
61   } else {
62      if (fb->zsbuf && util_format_get_blocksize(fb->zsbuf->format) > 2)
63         rt_format |= NV30_3D_RT_FORMAT_COLOR_A8R8G8B8;
64      else
65         rt_format |= NV30_3D_RT_FORMAT_COLOR_R5G6B5;
66   }
67
68   if (fb->zsbuf) {
69      rt_format |= nv30_format(pscreen, fb->zsbuf->format)->hw;
70      if (nv30_miptree(fb->zsbuf->texture)->swizzled)
71         rt_format |= NV30_3D_RT_FORMAT_TYPE_SWIZZLED;
72      else
73         rt_format |= NV30_3D_RT_FORMAT_TYPE_LINEAR;
74   } else {
75      if (fb->nr_cbufs && util_format_get_blocksize(fb->cbufs[0]->format) > 2)
76         rt_format |= NV30_3D_RT_FORMAT_ZETA_Z24S8;
77      else
78         rt_format |= NV30_3D_RT_FORMAT_ZETA_Z16;
79   }
80
81   /* hardware rounds down render target offset to 64 bytes, but surfaces
82    * with a size of 2x2 pixel (16bpp) or 1x1 pixel (32bpp) have an
83    * unaligned start aaddress.  For these two important square formats
84    * we can hack around this limitation by adjusting the viewport origin
85    */
86   if (nv30->state.rt_enable) {
87      int off = nv30_surface(fb->cbufs[0])->offset & 63;
88      if (off) {
89         x += off / (util_format_get_blocksize(fb->cbufs[0]->format) * 2);
90         w  = 16;
91         h  = 2;
92      }
93   }
94
95   if (rt_format & NV30_3D_RT_FORMAT_TYPE_SWIZZLED) {
96      rt_format |= util_logbase2(w) << 16;
97      rt_format |= util_logbase2(h) << 24;
98   }
99
100   if (!PUSH_SPACE(push, 64))
101      return;
102   PUSH_RESET(push, BUFCTX_FB);
103
104   BEGIN_NV04(push, SUBC_3D(0x1da4), 1);
105   PUSH_DATA (push, 0);
106   BEGIN_NV04(push, NV30_3D(RT_HORIZ), 3);
107   PUSH_DATA (push, w << 16);
108   PUSH_DATA (push, h << 16);
109   PUSH_DATA (push, rt_format);
110   BEGIN_NV04(push, NV30_3D(VIEWPORT_TX_ORIGIN), 4);
111   PUSH_DATA (push, (y << 16) | x);
112   PUSH_DATA (push, 0);
113   PUSH_DATA (push, ((w - 1) << 16) | 0);
114   PUSH_DATA (push, ((h - 1) << 16) | 0);
115
116   if ((nv30->state.rt_enable & NV30_3D_RT_ENABLE_COLOR0) || fb->zsbuf) {
117      struct nv30_surface *rsf = nv30_surface(fb->cbufs[0]);
118      struct nv30_surface *zsf = nv30_surface(fb->zsbuf);
119      struct nouveau_bo *rbo, *zbo;
120
121      if (!rsf)      rsf = zsf;
122      else if (!zsf) zsf = rsf;
123      rbo = nv30_miptree(rsf->base.texture)->base.bo;
124      zbo = nv30_miptree(zsf->base.texture)->base.bo;
125
126      if (eng3d->oclass >= NV40_3D_CLASS) {
127         BEGIN_NV04(push, NV40_3D(ZETA_PITCH), 1);
128         PUSH_DATA (push, zsf->pitch);
129         BEGIN_NV04(push, NV40_3D(COLOR0_PITCH), 3);
130         PUSH_DATA (push, rsf->pitch);
131      } else {
132         BEGIN_NV04(push, NV30_3D(COLOR0_PITCH), 3);
133         PUSH_DATA (push, (zsf->pitch << 16) | rsf->pitch);
134      }
135      PUSH_MTHDl(push, NV30_3D(COLOR0_OFFSET), BUFCTX_FB, rbo, rsf->offset & ~63,
136                       NOUVEAU_BO_VRAM | NOUVEAU_BO_RDWR);
137      PUSH_MTHDl(push, NV30_3D(ZETA_OFFSET), BUFCTX_FB, zbo, zsf->offset & ~63,
138                       NOUVEAU_BO_VRAM | NOUVEAU_BO_RDWR);
139   }
140
141   if (nv30->state.rt_enable & NV30_3D_RT_ENABLE_COLOR1) {
142      struct nv30_surface *sf = nv30_surface(fb->cbufs[1]);
143      struct nouveau_bo *bo = nv30_miptree(sf->base.texture)->base.bo;
144
145      BEGIN_NV04(push, NV30_3D(COLOR1_OFFSET), 2);
146      PUSH_MTHDl(push, NV30_3D(COLOR1_OFFSET), BUFCTX_FB, bo, sf->offset,
147                       NOUVEAU_BO_VRAM | NOUVEAU_BO_RDWR);
148      PUSH_DATA (push, sf->pitch);
149   }
150
151   if (nv30->state.rt_enable & NV40_3D_RT_ENABLE_COLOR2) {
152      struct nv30_surface *sf = nv30_surface(fb->cbufs[2]);
153      struct nouveau_bo *bo = nv30_miptree(sf->base.texture)->base.bo;
154
155      BEGIN_NV04(push, NV40_3D(COLOR2_OFFSET), 1);
156      PUSH_MTHDl(push, NV40_3D(COLOR2_OFFSET), BUFCTX_FB, bo, sf->offset,
157                       NOUVEAU_BO_VRAM | NOUVEAU_BO_RDWR);
158      BEGIN_NV04(push, NV40_3D(COLOR2_PITCH), 1);
159      PUSH_DATA (push, sf->pitch);
160   }
161
162   if (nv30->state.rt_enable & NV40_3D_RT_ENABLE_COLOR3) {
163      struct nv30_surface *sf = nv30_surface(fb->cbufs[3]);
164      struct nouveau_bo *bo = nv30_miptree(sf->base.texture)->base.bo;
165
166      BEGIN_NV04(push, NV40_3D(COLOR3_OFFSET), 1);
167      PUSH_MTHDl(push, NV40_3D(COLOR3_OFFSET), BUFCTX_FB, bo, sf->offset,
168                       NOUVEAU_BO_VRAM | NOUVEAU_BO_RDWR);
169      BEGIN_NV04(push, NV40_3D(COLOR3_PITCH), 1);
170      PUSH_DATA (push, sf->pitch);
171   }
172}
173
174static void
175nv30_validate_blend_colour(struct nv30_context *nv30)
176{
177   struct nouveau_pushbuf *push = nv30->base.pushbuf;
178   float *rgba = nv30->blend_colour.color;
179
180   if (nv30->framebuffer.nr_cbufs) {
181      switch (nv30->framebuffer.cbufs[0]->format) {
182      case PIPE_FORMAT_R16G16B16A16_FLOAT:
183      case PIPE_FORMAT_R32G32B32A32_FLOAT:
184         BEGIN_NV04(push, NV30_3D(BLEND_COLOR), 1);
185         PUSH_DATA (push, (util_float_to_half(rgba[0]) <<  0) |
186                          (util_float_to_half(rgba[1]) << 16));
187         BEGIN_NV04(push, SUBC_3D(0x037c), 1);
188         PUSH_DATA (push, (util_float_to_half(rgba[2]) <<  0) |
189                          (util_float_to_half(rgba[3]) << 16));
190         break;
191      default:
192         break;
193      }
194   }
195
196   BEGIN_NV04(push, NV30_3D(BLEND_COLOR), 1);
197   PUSH_DATA (push, (float_to_ubyte(rgba[3]) << 24) |
198                    (float_to_ubyte(rgba[0]) << 16) |
199                    (float_to_ubyte(rgba[1]) <<  8) |
200                    (float_to_ubyte(rgba[2]) <<  0));
201}
202
203static void
204nv30_validate_stencil_ref(struct nv30_context *nv30)
205{
206   struct nouveau_pushbuf *push = nv30->base.pushbuf;
207
208   BEGIN_NV04(push, NV30_3D(STENCIL_FUNC_REF(0)), 1);
209   PUSH_DATA (push, nv30->stencil_ref.ref_value[0]);
210   BEGIN_NV04(push, NV30_3D(STENCIL_FUNC_REF(1)), 1);
211   PUSH_DATA (push, nv30->stencil_ref.ref_value[1]);
212}
213
214static void
215nv30_validate_stipple(struct nv30_context *nv30)
216{
217   struct nouveau_pushbuf *push = nv30->base.pushbuf;
218
219   BEGIN_NV04(push, NV30_3D(POLYGON_STIPPLE_PATTERN(0)), 32);
220   PUSH_DATAp(push, nv30->stipple.stipple, 32);
221}
222
223static void
224nv30_validate_scissor(struct nv30_context *nv30)
225{
226   struct nouveau_pushbuf *push = nv30->base.pushbuf;
227   struct pipe_scissor_state *s = &nv30->scissor;
228   bool rast_scissor = nv30->rast ? nv30->rast->pipe.scissor : false;
229
230   if (!(nv30->dirty & NV30_NEW_SCISSOR) &&
231       rast_scissor != nv30->state.scissor_off)
232      return;
233   nv30->state.scissor_off = !rast_scissor;
234
235   BEGIN_NV04(push, NV30_3D(SCISSOR_HORIZ), 2);
236   if (rast_scissor) {
237      PUSH_DATA (push, ((s->maxx - s->minx) << 16) | s->minx);
238      PUSH_DATA (push, ((s->maxy - s->miny) << 16) | s->miny);
239   } else {
240      PUSH_DATA (push, 0x10000000);
241      PUSH_DATA (push, 0x10000000);
242   }
243}
244
245static void
246nv30_validate_viewport(struct nv30_context *nv30)
247{
248   struct nouveau_pushbuf *push = nv30->base.pushbuf;
249   struct pipe_viewport_state *vp = &nv30->viewport;
250
251   unsigned x = CLAMP(vp->translate[0] - fabsf(vp->scale[0]), 0, 4095);
252   unsigned y = CLAMP(vp->translate[1] - fabsf(vp->scale[1]), 0, 4095);
253   unsigned w = CLAMP(2.0f * fabsf(vp->scale[0]), 0, 4096);
254   unsigned h = CLAMP(2.0f * fabsf(vp->scale[1]), 0, 4096);
255
256   BEGIN_NV04(push, NV30_3D(VIEWPORT_TRANSLATE_X), 8);
257   PUSH_DATAf(push, vp->translate[0]);
258   PUSH_DATAf(push, vp->translate[1]);
259   PUSH_DATAf(push, vp->translate[2]);
260   PUSH_DATAf(push, 0.0f);
261   PUSH_DATAf(push, vp->scale[0]);
262   PUSH_DATAf(push, vp->scale[1]);
263   PUSH_DATAf(push, vp->scale[2]);
264   PUSH_DATAf(push, 0.0f);
265   BEGIN_NV04(push, NV30_3D(DEPTH_RANGE_NEAR), 2);
266   PUSH_DATAf(push, vp->translate[2] - fabsf(vp->scale[2]));
267   PUSH_DATAf(push, vp->translate[2] + fabsf(vp->scale[2]));
268
269   BEGIN_NV04(push, NV30_3D(VIEWPORT_HORIZ), 2);
270   PUSH_DATA (push, (w << 16) | x);
271   PUSH_DATA (push, (h << 16) | y);
272}
273
274static void
275nv30_validate_clip(struct nv30_context *nv30)
276{
277   struct nouveau_pushbuf *push = nv30->base.pushbuf;
278   unsigned i;
279   uint32_t clpd_enable = 0;
280
281   for (i = 0; i < 6; i++) {
282      if (nv30->dirty & NV30_NEW_CLIP) {
283         BEGIN_NV04(push, NV30_3D(VP_UPLOAD_CONST_ID), 5);
284         PUSH_DATA (push, i);
285         PUSH_DATAp(push, nv30->clip.ucp[i], 4);
286      }
287      if (nv30->rast->pipe.clip_plane_enable & (1 << i))
288         clpd_enable |= 2 << (4*i);
289   }
290
291   BEGIN_NV04(push, NV30_3D(VP_CLIP_PLANES_ENABLE), 1);
292   PUSH_DATA (push, clpd_enable);
293}
294
295static void
296nv30_validate_blend(struct nv30_context *nv30)
297{
298   struct nouveau_pushbuf *push = nv30->base.pushbuf;
299
300   PUSH_SPACE(push, nv30->blend->size);
301   PUSH_DATAp(push, nv30->blend->data, nv30->blend->size);
302}
303
304static void
305nv30_validate_zsa(struct nv30_context *nv30)
306{
307   struct nouveau_pushbuf *push = nv30->base.pushbuf;
308
309   PUSH_SPACE(push, nv30->zsa->size);
310   PUSH_DATAp(push, nv30->zsa->data, nv30->zsa->size);
311}
312
313static void
314nv30_validate_rasterizer(struct nv30_context *nv30)
315{
316   struct nouveau_pushbuf *push = nv30->base.pushbuf;
317
318   PUSH_SPACE(push, nv30->rast->size);
319   PUSH_DATAp(push, nv30->rast->data, nv30->rast->size);
320}
321
322static void
323nv30_validate_multisample(struct nv30_context *nv30)
324{
325   struct pipe_rasterizer_state *rasterizer = &nv30->rast->pipe;
326   struct pipe_blend_state *blend = &nv30->blend->pipe;
327   struct nouveau_pushbuf *push = nv30->base.pushbuf;
328   uint32_t ctrl = nv30->sample_mask << 16;
329
330   if (blend->alpha_to_one)
331      ctrl |= 0x00000100;
332   if (blend->alpha_to_coverage)
333      ctrl |= 0x00000010;
334   if (rasterizer->multisample)
335      ctrl |= 0x00000001;
336
337   BEGIN_NV04(push, NV30_3D(MULTISAMPLE_CONTROL), 1);
338   PUSH_DATA (push, ctrl);
339}
340
341static void
342nv30_validate_fragment(struct nv30_context *nv30)
343{
344   struct nouveau_pushbuf *push = nv30->base.pushbuf;
345   struct nv30_fragprog *fp = nv30->fragprog.program;
346
347   BEGIN_NV04(push, NV30_3D(RT_ENABLE), 1);
348   PUSH_DATA (push, nv30->state.rt_enable & (fp ? ~fp->rt_enable : 0x1f));
349   BEGIN_NV04(push, NV30_3D(COORD_CONVENTIONS), 1);
350   PUSH_DATA (push, (fp ? fp->coord_conventions : 0) | nv30->framebuffer.height);
351}
352
353static void
354nv30_validate_point_coord(struct nv30_context *nv30)
355{
356   struct pipe_rasterizer_state *rasterizer = &nv30->rast->pipe;
357   struct nouveau_pushbuf *push = nv30->base.pushbuf;
358   struct nv30_fragprog *fp = nv30->fragprog.program;
359   uint32_t hw = 0x00000000;
360
361   if (rasterizer) {
362      hw |= (nv30->rast->pipe.sprite_coord_enable & 0xff) << 8;
363      if (fp)
364         hw |= fp->point_sprite_control;
365
366      if (rasterizer->sprite_coord_mode == PIPE_SPRITE_COORD_LOWER_LEFT) {
367         if (hw)
368            nv30->draw_flags |= NV30_NEW_RASTERIZER;
369      } else
370      if (rasterizer->point_quad_rasterization) {
371         hw |= NV30_3D_POINT_SPRITE_ENABLE;
372      }
373   }
374
375   BEGIN_NV04(push, NV30_3D(POINT_SPRITE), 1);
376   PUSH_DATA (push, hw);
377}
378
379struct state_validate {
380   void (*func)(struct nv30_context *);
381   uint32_t mask;
382};
383
384static struct state_validate hwtnl_validate_list[] = {
385    { nv30_validate_fb,            NV30_NEW_FRAMEBUFFER },
386    { nv30_validate_blend,         NV30_NEW_BLEND },
387    { nv30_validate_zsa,           NV30_NEW_ZSA },
388    { nv30_validate_rasterizer,    NV30_NEW_RASTERIZER },
389    { nv30_validate_multisample,   NV30_NEW_SAMPLE_MASK | NV30_NEW_BLEND |
390                                   NV30_NEW_RASTERIZER },
391    { nv30_validate_blend_colour,  NV30_NEW_BLEND_COLOUR |
392                                   NV30_NEW_FRAMEBUFFER },
393    { nv30_validate_stencil_ref,   NV30_NEW_STENCIL_REF },
394    { nv30_validate_stipple,       NV30_NEW_STIPPLE },
395    { nv30_validate_scissor,       NV30_NEW_SCISSOR | NV30_NEW_RASTERIZER },
396    { nv30_validate_viewport,      NV30_NEW_VIEWPORT },
397    { nv30_validate_clip,          NV30_NEW_CLIP | NV30_NEW_RASTERIZER },
398    { nv30_fragprog_validate,      NV30_NEW_FRAGPROG | NV30_NEW_FRAGCONST },
399    { nv30_vertprog_validate,      NV30_NEW_VERTPROG | NV30_NEW_VERTCONST |
400                                   NV30_NEW_FRAGPROG | NV30_NEW_RASTERIZER },
401    { nv30_validate_fragment,      NV30_NEW_FRAMEBUFFER | NV30_NEW_FRAGPROG },
402    { nv30_validate_point_coord,   NV30_NEW_RASTERIZER | NV30_NEW_FRAGPROG },
403    { nv30_fragtex_validate,       NV30_NEW_FRAGTEX },
404    { nv40_verttex_validate,       NV30_NEW_VERTTEX },
405    { nv30_vbo_validate,           NV30_NEW_VERTEX | NV30_NEW_ARRAYS },
406    {}
407};
408
409#define NV30_SWTNL_MASK (NV30_NEW_VIEWPORT |  \
410                         NV30_NEW_CLIP |      \
411                         NV30_NEW_VERTPROG |  \
412                         NV30_NEW_VERTCONST | \
413                         NV30_NEW_VERTTEX |   \
414                         NV30_NEW_VERTEX |    \
415                         NV30_NEW_ARRAYS)
416
417static struct state_validate swtnl_validate_list[] = {
418    { nv30_validate_fb,            NV30_NEW_FRAMEBUFFER },
419    { nv30_validate_blend,         NV30_NEW_BLEND },
420    { nv30_validate_zsa,           NV30_NEW_ZSA },
421    { nv30_validate_rasterizer,    NV30_NEW_RASTERIZER },
422    { nv30_validate_multisample,   NV30_NEW_SAMPLE_MASK | NV30_NEW_BLEND |
423                                   NV30_NEW_RASTERIZER },
424    { nv30_validate_blend_colour,  NV30_NEW_BLEND_COLOUR |
425                                   NV30_NEW_FRAMEBUFFER },
426    { nv30_validate_stencil_ref,   NV30_NEW_STENCIL_REF },
427    { nv30_validate_stipple,       NV30_NEW_STIPPLE },
428    { nv30_validate_scissor,       NV30_NEW_SCISSOR | NV30_NEW_RASTERIZER },
429    { nv30_fragprog_validate,      NV30_NEW_FRAGPROG | NV30_NEW_FRAGCONST },
430    { nv30_validate_fragment,      NV30_NEW_FRAMEBUFFER | NV30_NEW_FRAGPROG },
431    { nv30_fragtex_validate,       NV30_NEW_FRAGTEX },
432    {}
433};
434
435static void
436nv30_state_context_switch(struct nv30_context *nv30)
437{
438   struct nv30_context *prev = nv30->screen->cur_ctx;
439
440   if (prev)
441      nv30->state = prev->state;
442   nv30->dirty = NV30_NEW_ALL;
443
444   if (!nv30->vertex)
445      nv30->dirty &= ~(NV30_NEW_VERTEX | NV30_NEW_ARRAYS);
446
447   if (!nv30->vertprog.program)
448      nv30->dirty &= ~NV30_NEW_VERTPROG;
449   if (!nv30->fragprog.program)
450      nv30->dirty &= ~NV30_NEW_FRAGPROG;
451
452   if (!nv30->blend)
453      nv30->dirty &= ~NV30_NEW_BLEND;
454   if (!nv30->rast)
455      nv30->dirty &= ~NV30_NEW_RASTERIZER;
456   if (!nv30->zsa)
457      nv30->dirty &= ~NV30_NEW_ZSA;
458
459   nv30->screen->cur_ctx = nv30;
460   nv30->base.pushbuf->user_priv = &nv30->bufctx;
461}
462
463bool
464nv30_state_validate(struct nv30_context *nv30, uint32_t mask, bool hwtnl)
465{
466   struct nouveau_screen *screen = &nv30->screen->base;
467   struct nouveau_pushbuf *push = nv30->base.pushbuf;
468   struct nouveau_bufctx *bctx = nv30->bufctx;
469   struct nouveau_bufref *bref;
470   struct state_validate *validate;
471
472   if (nv30->screen->cur_ctx != nv30)
473      nv30_state_context_switch(nv30);
474
475   if (hwtnl) {
476      nv30->draw_dirty |= nv30->dirty;
477      if (nv30->draw_flags) {
478         nv30->draw_flags &= ~nv30->dirty;
479         if (!nv30->draw_flags)
480            nv30->dirty |= NV30_SWTNL_MASK;
481      }
482   }
483
484   if (!nv30->draw_flags)
485      validate = hwtnl_validate_list;
486   else
487      validate = swtnl_validate_list;
488
489   mask &= nv30->dirty;
490
491   if (mask) {
492      while (validate->func) {
493         if (mask & validate->mask)
494            validate->func(nv30);
495         validate++;
496      }
497
498      nv30->dirty &= ~mask;
499   }
500
501   nouveau_pushbuf_bufctx(push, bctx);
502   if (nouveau_pushbuf_validate(push)) {
503      nouveau_pushbuf_bufctx(push, NULL);
504      return false;
505   }
506
507   /*XXX*/
508   BEGIN_NV04(push, NV30_3D(VTX_CACHE_INVALIDATE_1710), 1);
509   PUSH_DATA (push, 0);
510   if (nv30->screen->eng3d->oclass >= NV40_3D_CLASS) {
511      BEGIN_NV04(push, NV40_3D(TEX_CACHE_CTL), 1);
512      PUSH_DATA (push, 2);
513      BEGIN_NV04(push, NV40_3D(TEX_CACHE_CTL), 1);
514      PUSH_DATA (push, 1);
515      BEGIN_NV04(push, NV30_3D(R1718), 1);
516      PUSH_DATA (push, 0);
517      BEGIN_NV04(push, NV30_3D(R1718), 1);
518      PUSH_DATA (push, 0);
519      BEGIN_NV04(push, NV30_3D(R1718), 1);
520      PUSH_DATA (push, 0);
521   }
522
523   LIST_FOR_EACH_ENTRY(bref, &bctx->current, thead) {
524      struct nv04_resource *res = bref->priv;
525      if (res && res->mm) {
526         nouveau_fence_ref(screen->fence.current, &res->fence);
527
528         if (bref->flags & NOUVEAU_BO_RD)
529            res->status |= NOUVEAU_BUFFER_STATUS_GPU_READING;
530
531         if (bref->flags & NOUVEAU_BO_WR) {
532            nouveau_fence_ref(screen->fence.current, &res->fence_wr);
533            res->status |= NOUVEAU_BUFFER_STATUS_GPU_WRITING;
534         }
535      }
536   }
537
538   return true;
539}
540
541void
542nv30_state_release(struct nv30_context *nv30)
543{
544   nouveau_pushbuf_bufctx(nv30->base.pushbuf, NULL);
545}
546