#include "nv40_context.h" #include "nv40_state.h" /* Emit relocs for every referenced buffer. * * This is to ensure the bufmgr has an accurate idea of how * the buffer is used. These relocs appear in the push buffer as * NOPs, and will only be turned into state changes if a buffer * actually moves. */ static void nv40_state_emit_dummy_relocs(struct nv40_context *nv40) { unsigned i; so_emit_reloc_markers(nv40->nvws, nv40->so_framebuffer); for (i = 0; i < 16; i++) { if (!(nv40->fp_samplers & (1 << i))) continue; so_emit_reloc_markers(nv40->nvws, nv40->so_fragtex[i]); } so_emit_reloc_markers(nv40->nvws, nv40->fragprog.active->so); } static boolean nv40_state_scissor_validate(struct nv40_context *nv40) { struct pipe_rasterizer_state *rast = &nv40->rasterizer->pipe; struct pipe_scissor_state *s = &nv40->pipe_state.scissor; struct nouveau_stateobj *so; if (nv40->state.scissor.so && (rast->scissor == 0 && nv40->state.scissor.enabled == 0)) return FALSE; so = so_new(3, 0); so_method(so, nv40->hw->curie, NV40TCL_SCISSOR_HORIZ, 2); if (rast->scissor) { so_data (so, ((s->maxx - s->minx) << 16) | s->minx); so_data (so, ((s->maxy - s->miny) << 16) | s->miny); } else { so_data (so, 4096 << 16); so_data (so, 4096 << 16); } so_ref(so, &nv40->state.scissor.so); so_ref(NULL, &so); return TRUE; } static boolean nv40_state_stipple_validate(struct nv40_context *nv40) { struct pipe_rasterizer_state *rast = &nv40->rasterizer->pipe; struct nouveau_grobj *curie = nv40->hw->curie; struct nouveau_stateobj *so; if (nv40->state.stipple.so && (rast->poly_stipple_enable == 0 && nv40->state.stipple.enabled == 0)) return FALSE; if (rast->poly_stipple_enable) { unsigned i; so = so_new(35, 0); so_method(so, curie, NV40TCL_POLYGON_STIPPLE_ENABLE, 1); so_data (so, 1); so_method(so, curie, NV40TCL_POLYGON_STIPPLE_PATTERN(0), 32); for (i = 0; i < 32; i++) so_data(so, nv40->pipe_state.stipple[i]); } else { so = so_new(2, 0); so_method(so, curie, NV40TCL_POLYGON_STIPPLE_ENABLE, 1); so_data (so, 0); } so_ref(so, &nv40->state.stipple.so); so_ref(NULL, &so); return TRUE; } static boolean nv40_state_clip_validate(struct nv40_context *nv40) { if (nv40->pipe_state.clip.nr) nv40->fallback |= NV40_FALLBACK_TNL; return FALSE; } static struct nv40_state_entry states[] = { { .validate = nv40_state_scissor_validate, .dirty = { .pipe = NV40_NEW_SCISSOR | NV40_NEW_RAST, .hw = NV40_NEW_SCISSOR, } }, { .validate = nv40_state_stipple_validate, .dirty = { .pipe = NV40_NEW_STIPPLE | NV40_NEW_RAST, .hw = NV40_NEW_STIPPLE, } }, { .validate = nv40_state_clip_validate, .dirty = { .pipe = NV40_NEW_UCP, .hw = 0, } } }; static void nv40_state_validate(struct nv40_context *nv40) { unsigned i, last_fallback; last_fallback = nv40->fallback; nv40->fallback = 0; for (i = 0; i < sizeof(states) / sizeof(states[0]); i++) { if (nv40->dirty & states[i].dirty.pipe) { if (states[i].validate(nv40)) nv40->hw_dirty |= states[i].dirty.hw; } } if (nv40->fallback & NV40_FALLBACK_TNL && !(last_fallback & NV40_FALLBACK_TNL)) { NOUVEAU_ERR("XXX: hwtnl->swtnl\n"); } else if (last_fallback & NV40_FALLBACK_TNL && !(nv40->fallback & NV40_FALLBACK_TNL)) { NOUVEAU_ERR("XXX: swtnl->hwtnl\n"); } } void nv40_emit_hw_state(struct nv40_context *nv40) { nv40_state_validate(nv40); if (nv40->dirty & NV40_NEW_FB) so_emit(nv40->nvws, nv40->so_framebuffer); if (nv40->dirty & NV40_NEW_BLEND) so_emit(nv40->nvws, nv40->so_blend); if (nv40->dirty & NV40_NEW_RAST) so_emit(nv40->nvws, nv40->so_rast); if (nv40->dirty & NV40_NEW_ZSA) so_emit(nv40->nvws, nv40->so_zsa); if (nv40->dirty & NV40_NEW_BCOL) so_emit(nv40->nvws, nv40->so_bcol); if (nv40->hw_dirty & NV40_NEW_SCISSOR) { so_emit(nv40->nvws, nv40->state.scissor.so); nv40->hw_dirty &= ~NV40_NEW_SCISSOR; } if (nv40->dirty & NV40_NEW_VIEWPORT) so_emit(nv40->nvws, nv40->so_viewport); if (nv40->hw_dirty & NV40_NEW_STIPPLE) { so_emit(nv40->nvws, nv40->state.stipple.so); nv40->hw_dirty &= ~NV40_NEW_STIPPLE; } if (nv40->dirty & NV40_NEW_FRAGPROG) { nv40_fragprog_bind(nv40, nv40->fragprog.current); /*XXX: clear NV40_NEW_FRAGPROG if no new program uploaded */ } if (nv40->dirty_samplers || (nv40->dirty & NV40_NEW_FRAGPROG)) { nv40_fragtex_bind(nv40); BEGIN_RING(curie, NV40TCL_TEX_CACHE_CTL, 1); OUT_RING (2); BEGIN_RING(curie, NV40TCL_TEX_CACHE_CTL, 1); OUT_RING (1); nv40->dirty &= ~NV40_NEW_FRAGPROG; } if (nv40->dirty & NV40_NEW_VERTPROG) { nv40_vertprog_bind(nv40, nv40->vertprog.current); nv40->dirty &= ~NV40_NEW_VERTPROG; } nv40->dirty_samplers = 0; nv40->dirty = 0; nv40_state_emit_dummy_relocs(nv40); }