#include "nv50_context.h"
#include "nouveau/nouveau_stateobj.h"
-static void
-nv50_state_validate_fb(struct nv50_context *nv50)
+static struct nouveau_stateobj *
+validate_fb(struct nv50_context *nv50)
{
struct nouveau_grobj *tesla = nv50->screen->tesla;
struct nouveau_stateobj *so = so_new(32, 79, 18);
/* we set scissors to framebuffer size when they're 'turned off' */
nv50->dirty |= NV50_NEW_SCISSOR;
- so_ref(NULL, &nv50->state.scissor);
-
- so_ref(so, &nv50->state.fb);
- so_ref(NULL, &so);
+ so_ref(NULL, &nv50->state.hw[12]);
+ return so;
}
static void
}
}
-static void
-nv50_state_emit(struct nv50_context *nv50)
+static struct nouveau_stateobj *
+validate_blend(struct nv50_context *nv50)
{
- struct nv50_screen *screen = nv50->screen;
- struct nouveau_channel *chan = screen->base.channel;
+ struct nouveau_stateobj *so = NULL;
+ so_ref(nv50->blend->so, &so);
+ return so;
+}
- /* XXX: this is racy for multiple contexts active on separate
- * threads.
- */
- if (screen->cur_ctx != nv50) {
- if (nv50->state.fb)
- nv50->state.dirty |= NV50_NEW_FRAMEBUFFER;
- if (nv50->state.blend)
- nv50->state.dirty |= NV50_NEW_BLEND;
- if (nv50->state.zsa)
- nv50->state.dirty |= NV50_NEW_ZSA;
- if (nv50->state.vertprog)
- nv50->state.dirty |= NV50_NEW_VERTPROG;
- if (nv50->state.fragprog)
- nv50->state.dirty |= NV50_NEW_FRAGPROG;
- if (nv50->state.geomprog)
- nv50->state.dirty |= NV50_NEW_GEOMPROG;
- if (nv50->state.rast)
- nv50->state.dirty |= NV50_NEW_RASTERIZER;
- if (nv50->state.blend_colour)
- nv50->state.dirty |= NV50_NEW_BLEND_COLOUR;
- if (nv50->state.stencil_ref)
- nv50->state.dirty |= NV50_NEW_STENCIL_REF;
- if (nv50->state.stipple)
- nv50->state.dirty |= NV50_NEW_STIPPLE;
- if (nv50->state.scissor)
- nv50->state.dirty |= NV50_NEW_SCISSOR;
- if (nv50->state.viewport)
- nv50->state.dirty |= NV50_NEW_VIEWPORT;
- if (nv50->state.tsc_upload)
- nv50->state.dirty |= NV50_NEW_SAMPLER;
- if (nv50->state.tic_upload)
- nv50->state.dirty |= NV50_NEW_TEXTURE;
- if (nv50->state.vtxfmt && nv50->state.vtxbuf)
- nv50->state.dirty |= NV50_NEW_ARRAYS;
- screen->cur_ctx = nv50;
- }
+static struct nouveau_stateobj *
+validate_zsa(struct nv50_context *nv50)
+{
+ struct nouveau_stateobj *so = NULL;
+ so_ref(nv50->zsa->so, &so);
+ return so;
+}
- if (nv50->state.dirty & NV50_NEW_FRAMEBUFFER)
- so_emit(chan, nv50->state.fb);
- if (nv50->state.dirty & NV50_NEW_BLEND)
- so_emit(chan, nv50->state.blend);
- if (nv50->state.dirty & NV50_NEW_ZSA)
- so_emit(chan, nv50->state.zsa);
- if (nv50->state.dirty & NV50_NEW_VERTPROG)
- so_emit(chan, nv50->state.vertprog);
- if (nv50->state.dirty & NV50_NEW_FRAGPROG)
- so_emit(chan, nv50->state.fragprog);
- if (nv50->state.dirty & NV50_NEW_GEOMPROG && nv50->state.geomprog)
- so_emit(chan, nv50->state.geomprog);
- if (nv50->state.dirty & (NV50_NEW_FRAGPROG | NV50_NEW_VERTPROG |
- NV50_NEW_GEOMPROG | NV50_NEW_RASTERIZER))
- so_emit(chan, nv50->state.fp_linkage);
- if ((nv50->state.dirty & (NV50_NEW_VERTPROG | NV50_NEW_GEOMPROG))
- && nv50->state.gp_linkage)
- so_emit(chan, nv50->state.gp_linkage);
- if (nv50->state.dirty & NV50_NEW_RASTERIZER)
- so_emit(chan, nv50->state.rast);
- if (nv50->state.dirty & NV50_NEW_BLEND_COLOUR)
- so_emit(chan, nv50->state.blend_colour);
- if (nv50->state.dirty & NV50_NEW_STENCIL_REF)
- so_emit(chan, nv50->state.stencil_ref);
- if (nv50->state.dirty & NV50_NEW_STIPPLE)
- so_emit(chan, nv50->state.stipple);
- if (nv50->state.dirty & NV50_NEW_SCISSOR)
- so_emit(chan, nv50->state.scissor);
- if (nv50->state.dirty & NV50_NEW_VIEWPORT)
- so_emit(chan, nv50->state.viewport);
- if (nv50->state.dirty & NV50_NEW_SAMPLER)
- so_emit(chan, nv50->state.tsc_upload);
- if (nv50->state.dirty & NV50_NEW_TEXTURE)
- so_emit(chan, nv50->state.tic_upload);
- if (nv50->state.dirty & NV50_NEW_ARRAYS) {
- so_emit(chan, nv50->state.vtxfmt);
- so_emit(chan, nv50->state.vtxbuf);
- if (nv50->state.vtxattr)
- so_emit(chan, nv50->state.vtxattr);
- }
- nv50->state.dirty = 0;
+static struct nouveau_stateobj *
+validate_rast(struct nv50_context *nv50)
+{
+ struct nouveau_stateobj *so = NULL;
+ so_ref(nv50->rasterizer->so, &so);
+ return so;
}
-void
-nv50_state_flush_notify(struct nouveau_channel *chan)
+static struct nouveau_stateobj *
+validate_blend_colour(struct nv50_context *nv50)
{
- struct nv50_context *nv50 = chan->user_private;
+ struct nouveau_grobj *tesla = nv50->screen->tesla;
+ struct nouveau_stateobj *so = so_new(1, 4, 0);
+
+ so_method(so, tesla, NV50TCL_BLEND_COLOR(0), 4);
+ so_data (so, fui(nv50->blend_colour.color[0]));
+ so_data (so, fui(nv50->blend_colour.color[1]));
+ so_data (so, fui(nv50->blend_colour.color[2]));
+ so_data (so, fui(nv50->blend_colour.color[3]));
+ return so;
+}
- nv50_tex_relocs(nv50);
+static struct nouveau_stateobj *
+validate_stencil_ref(struct nv50_context *nv50)
+{
+ struct nouveau_grobj *tesla = nv50->screen->tesla;
+ struct nouveau_stateobj *so = so = so_new(2, 2, 0);
- so_emit_reloc_markers(chan, nv50->state.fb);
- so_emit_reloc_markers(chan, nv50->state.vertprog);
- so_emit_reloc_markers(chan, nv50->state.fragprog);
- so_emit_reloc_markers(chan, nv50->state.vtxbuf);
- so_emit_reloc_markers(chan, nv50->screen->static_init);
+ so_method(so, tesla, NV50TCL_STENCIL_FRONT_FUNC_REF, 1);
+ so_data (so, nv50->stencil_ref.ref_value[0]);
+ so_method(so, tesla, NV50TCL_STENCIL_BACK_FUNC_REF, 1);
+ so_data (so, nv50->stencil_ref.ref_value[1]);
+ return so;
+}
- if (nv50->state.instbuf)
- so_emit_reloc_markers(chan, nv50->state.instbuf);
+static struct nouveau_stateobj *
+validate_stipple(struct nv50_context *nv50)
+{
+ struct nouveau_grobj *tesla = nv50->screen->tesla;
+ struct nouveau_stateobj *so = so_new(1, 32, 0);
+ int i;
+
+ so_method(so, tesla, NV50TCL_POLYGON_STIPPLE_PATTERN(0), 32);
+ for (i = 0; i < 32; i++)
+ so_data(so, util_bswap32(nv50->stipple.stipple[i]));
+ return so;
}
-boolean
-nv50_state_validate(struct nv50_context *nv50)
+static struct nouveau_stateobj *
+validate_scissor(struct nv50_context *nv50)
{
+ struct pipe_rasterizer_state *rast = &nv50->rasterizer->pipe;
+ struct pipe_scissor_state *s = &nv50->scissor;
struct nouveau_grobj *tesla = nv50->screen->tesla;
struct nouveau_stateobj *so;
- unsigned i;
- if (nv50->dirty & NV50_NEW_FRAMEBUFFER)
- nv50_state_validate_fb(nv50);
+ if (nv50->state.hw[12] &&
+ (rast->scissor == 0 && nv50->state.scissor_enabled == 0))
+ return NULL;
+ nv50->state.scissor_enabled = rast->scissor;
- if (nv50->dirty & NV50_NEW_BLEND)
- so_ref(nv50->blend->so, &nv50->state.blend);
+ so = so_new(1, 2, 0);
+ so_method(so, tesla, NV50TCL_SCISSOR_HORIZ(0), 2);
+ if (nv50->state.scissor_enabled) {
+ so_data(so, (s->maxx << 16) | s->minx);
+ so_data(so, (s->maxy << 16) | s->miny);
+ } else {
+ so_data(so, (nv50->framebuffer.width << 16));
+ so_data(so, (nv50->framebuffer.height << 16));
+ }
- if (nv50->dirty & NV50_NEW_ZSA)
- so_ref(nv50->zsa->so, &nv50->state.zsa);
+ return so;
+}
- if (nv50->dirty & (NV50_NEW_VERTPROG | NV50_NEW_VERTPROG_CB))
- nv50_vertprog_validate(nv50);
+static struct nouveau_stateobj *
+validate_viewport(struct nv50_context *nv50)
+{
+ struct nouveau_grobj *tesla = nv50->screen->tesla;
+ struct nouveau_stateobj *so = so_new(5, 9, 0);
+
+ so_method(so, tesla, NV50TCL_VIEWPORT_TRANSLATE_X(0), 3);
+ so_data (so, fui(nv50->viewport.translate[0]));
+ so_data (so, fui(nv50->viewport.translate[1]));
+ so_data (so, fui(nv50->viewport.translate[2]));
+ so_method(so, tesla, NV50TCL_VIEWPORT_SCALE_X(0), 3);
+ so_data (so, fui(nv50->viewport.scale[0]));
+ so_data (so, fui(nv50->viewport.scale[1]));
+ so_data (so, fui(nv50->viewport.scale[2]));
+
+ so_method(so, tesla, NV50TCL_VIEWPORT_TRANSFORM_EN, 1);
+ so_data (so, 1);
+ /* 0x0000 = remove whole primitive only (xyz)
+ * 0x1018 = remove whole primitive only (xy), clamp z
+ * 0x1080 = clip primitive (xyz)
+ * 0x1098 = clip primitive (xy), clamp z
+ */
+ so_method(so, tesla, NV50TCL_VIEW_VOLUME_CLIP_CTRL, 1);
+ so_data (so, 0x1080);
+ /* no idea what 0f90 does */
+ so_method(so, tesla, 0x0f90, 1);
+ so_data (so, 0);
- if (nv50->dirty & (NV50_NEW_FRAGPROG | NV50_NEW_FRAGPROG_CB))
- nv50_fragprog_validate(nv50);
+ return so;
+}
- if (nv50->dirty & (NV50_NEW_GEOMPROG | NV50_NEW_GEOMPROG_CB))
- nv50_geomprog_validate(nv50);
+static struct nouveau_stateobj *
+validate_sampler(struct nv50_context *nv50)
+{
+ struct nouveau_grobj *tesla = nv50->screen->tesla;
+ struct nouveau_stateobj *so;
+ unsigned nr = 0, i;
- if (nv50->dirty & (NV50_NEW_FRAGPROG | NV50_NEW_VERTPROG |
- NV50_NEW_GEOMPROG | NV50_NEW_RASTERIZER))
- nv50_fp_linkage_validate(nv50);
+ for (i = 0; i < PIPE_SHADER_TYPES; ++i)
+ nr += nv50->sampler_nr[i];
- if (nv50->dirty & (NV50_NEW_GEOMPROG | NV50_NEW_VERTPROG))
- nv50_gp_linkage_validate(nv50);
+ so = so_new(1 + 5 * PIPE_SHADER_TYPES,
+ 1 + 19 * PIPE_SHADER_TYPES + nr * 8,
+ PIPE_SHADER_TYPES * 2);
- if (nv50->dirty & NV50_NEW_RASTERIZER)
- so_ref(nv50->rasterizer->so, &nv50->state.rast);
+ nv50_validate_samplers(nv50, so, PIPE_SHADER_VERTEX);
+ nv50_validate_samplers(nv50, so, PIPE_SHADER_FRAGMENT);
- if (nv50->dirty & NV50_NEW_BLEND_COLOUR) {
- so = so_new(1, 4, 0);
- so_method(so, tesla, NV50TCL_BLEND_COLOR(0), 4);
- so_data (so, fui(nv50->blend_colour.color[0]));
- so_data (so, fui(nv50->blend_colour.color[1]));
- so_data (so, fui(nv50->blend_colour.color[2]));
- so_data (so, fui(nv50->blend_colour.color[3]));
- so_ref(so, &nv50->state.blend_colour);
- so_ref(NULL, &so);
- }
-
- if (nv50->dirty & NV50_NEW_STENCIL_REF) {
- so = so_new(2, 2, 0);
- so_method(so, tesla, NV50TCL_STENCIL_FRONT_FUNC_REF, 1);
- so_data (so, nv50->stencil_ref.ref_value[0]);
- so_method(so, tesla, NV50TCL_STENCIL_BACK_FUNC_REF, 1);
- so_data (so, nv50->stencil_ref.ref_value[1]);
- so_ref(so, &nv50->state.stencil_ref);
- so_ref(NULL, &so);
- }
+ so_method(so, tesla, 0x1334, 1); /* flush TSC */
+ so_data (so, 0);
- if (nv50->dirty & NV50_NEW_STIPPLE) {
- so = so_new(1, 32, 0);
- so_method(so, tesla, NV50TCL_POLYGON_STIPPLE_PATTERN(0), 32);
- for (i = 0; i < 32; i++)
- so_data(so, util_bswap32(nv50->stipple.stipple[i]));
- so_ref(so, &nv50->state.stipple);
- so_ref(NULL, &so);
- }
+ return so;
+}
- if (nv50->dirty & (NV50_NEW_SCISSOR | NV50_NEW_RASTERIZER)) {
- struct pipe_rasterizer_state *rast = &nv50->rasterizer->pipe;
- struct pipe_scissor_state *s = &nv50->scissor;
+static struct nouveau_stateobj *
+validate_vtxbuf(struct nv50_context *nv50)
+{
+ struct nouveau_stateobj *so = NULL;
+ so_ref(nv50->state.vtxbuf, &so);
+ return so;
+}
- if (nv50->state.scissor &&
- (rast->scissor == 0 && nv50->state.scissor_enabled == 0))
- goto scissor_uptodate;
- nv50->state.scissor_enabled = rast->scissor;
+static struct nouveau_stateobj *
+validate_vtxattr(struct nv50_context *nv50)
+{
+ struct nouveau_stateobj *so = NULL;
+ so_ref(nv50->state.vtxattr, &so);
+ return so;
+}
- so = so_new(1, 2, 0);
- so_method(so, tesla, NV50TCL_SCISSOR_HORIZ(0), 2);
- if (nv50->state.scissor_enabled) {
- so_data(so, (s->maxx << 16) | s->minx);
- so_data(so, (s->maxy << 16) | s->miny);
- } else {
- so_data(so, (nv50->framebuffer.width << 16));
- so_data(so, (nv50->framebuffer.height << 16));
- }
- so_ref(so, &nv50->state.scissor);
- so_ref(NULL, &so);
- nv50->state.dirty |= NV50_NEW_SCISSOR;
- }
-scissor_uptodate:
-
- if (nv50->dirty & (NV50_NEW_VIEWPORT | NV50_NEW_RASTERIZER)) {
- if (nv50->state.viewport &&
- !(nv50->dirty & NV50_NEW_VIEWPORT))
- goto viewport_uptodate;
-
- so = so_new(5, 9, 0);
- so_method(so, tesla, NV50TCL_VIEWPORT_TRANSLATE_X(0), 3);
- so_data (so, fui(nv50->viewport.translate[0]));
- so_data (so, fui(nv50->viewport.translate[1]));
- so_data (so, fui(nv50->viewport.translate[2]));
- so_method(so, tesla, NV50TCL_VIEWPORT_SCALE_X(0), 3);
- so_data (so, fui(nv50->viewport.scale[0]));
- so_data (so, fui(nv50->viewport.scale[1]));
- so_data (so, fui(nv50->viewport.scale[2]));
-
- so_method(so, tesla, NV50TCL_VIEWPORT_TRANSFORM_EN, 1);
- so_data (so, 1);
- /* 0x0000 = remove whole primitive only (xyz)
- * 0x1018 = remove whole primitive only (xy), clamp z
- * 0x1080 = clip primitive (xyz)
- * 0x1098 = clip primitive (xy), clamp z
- */
- so_method(so, tesla, NV50TCL_VIEW_VOLUME_CLIP_CTRL, 1);
- so_data (so, 0x1080);
- /* no idea what 0f90 does */
- so_method(so, tesla, 0x0f90, 1);
- so_data (so, 0);
+struct state_validate {
+ struct nouveau_stateobj *(*func)(struct nv50_context *nv50);
+ unsigned states;
+} validate_list[] = {
+ { validate_fb , NV50_NEW_FRAMEBUFFER },
+ { validate_blend , NV50_NEW_BLEND },
+ { validate_zsa , NV50_NEW_ZSA },
+ { nv50_vertprog_validate , NV50_NEW_VERTPROG | NV50_NEW_VERTPROG_CB },
+ { nv50_fragprog_validate , NV50_NEW_FRAGPROG | NV50_NEW_FRAGPROG_CB },
+ { nv50_geomprog_validate , NV50_NEW_GEOMPROG | NV50_NEW_GEOMPROG_CB },
+ { nv50_fp_linkage_validate, NV50_NEW_VERTPROG | NV50_NEW_GEOMPROG |
+ NV50_NEW_FRAGPROG | NV50_NEW_RASTERIZER },
+ { nv50_gp_linkage_validate, NV50_NEW_VERTPROG | NV50_NEW_GEOMPROG },
+ { validate_rast , NV50_NEW_RASTERIZER },
+ { validate_blend_colour , NV50_NEW_BLEND_COLOUR },
+ { validate_stencil_ref , NV50_NEW_STENCIL_REF },
+ { validate_stipple , NV50_NEW_STIPPLE },
+ { validate_scissor , NV50_NEW_SCISSOR | NV50_NEW_RASTERIZER },
+ { validate_viewport , NV50_NEW_VIEWPORT },
+ { validate_sampler , NV50_NEW_SAMPLER },
+ { nv50_tex_validate , NV50_NEW_TEXTURE | NV50_NEW_SAMPLER },
+ { nv50_vbo_validate , NV50_NEW_ARRAYS },
+ { validate_vtxbuf , NV50_NEW_ARRAYS },
+ { validate_vtxattr , NV50_NEW_ARRAYS },
+ {}
+};
+#define validate_list_len (sizeof(validate_list) / sizeof(validate_list[0]))
- so_ref(so, &nv50->state.viewport);
- so_ref(NULL, &so);
- nv50->state.dirty |= NV50_NEW_VIEWPORT;
- }
-viewport_uptodate:
+void
+nv50_state_flush_notify(struct nouveau_channel *chan)
+{
+ struct nv50_context *nv50 = chan->user_private;
- if (nv50->dirty & NV50_NEW_SAMPLER) {
- unsigned nr = 0;
+ nv50_tex_relocs(nv50);
- for (i = 0; i < PIPE_SHADER_TYPES; ++i)
- nr += nv50->sampler_nr[i];
+ so_emit_reloc_markers(chan, nv50->state.hw[0]); /* fb */
+ so_emit_reloc_markers(chan, nv50->state.hw[3]); /* vp */
+ so_emit_reloc_markers(chan, nv50->state.hw[4]); /* fp */
+ so_emit_reloc_markers(chan, nv50->state.hw[17]); /* vb */
+ so_emit_reloc_markers(chan, nv50->screen->static_init);
- so = so_new(1 + 5 * PIPE_SHADER_TYPES,
- 1 + 19 * PIPE_SHADER_TYPES + nr * 8,
- PIPE_SHADER_TYPES * 2);
+#if 0
+ if (nv50->state.instbuf)
+ so_emit_reloc_markers(chan, nv50->state.instbuf);
+#endif
+}
- nv50_validate_samplers(nv50, so, PIPE_SHADER_VERTEX);
- nv50_validate_samplers(nv50, so, PIPE_SHADER_FRAGMENT);
+boolean
+nv50_state_validate(struct nv50_context *nv50)
+{
+ struct nouveau_channel *chan = nv50->screen->base.channel;
+ int i;
- so_method(so, tesla, 0x1334, 1); /* flush TSC */
- so_data (so, 0);
+ if (nv50->screen->cur_ctx != nv50) {
+ for (i = 0; i < validate_list_len; i++) {
+ if (nv50->state.hw[i])
+ nv50->state.hw_dirty |= (1 << i);
+ }
- so_ref(so, &nv50->state.tsc_upload);
- so_ref(NULL, &so);
+ nv50->screen->cur_ctx = nv50;
}
- if (nv50->dirty & (NV50_NEW_TEXTURE | NV50_NEW_SAMPLER))
- nv50_tex_validate(nv50);
+ for (i = 0; i < validate_list_len; i++) {
+ struct state_validate *validate = &validate_list[i];
+ struct nouveau_stateobj *so;
+
+ if (!(nv50->dirty & validate->states))
+ continue;
- if (nv50->dirty & NV50_NEW_ARRAYS)
- nv50_vbo_validate(nv50);
+ so = validate->func(nv50);
+ if (!so)
+ continue;
- nv50->state.dirty |= nv50->dirty;
+ so_ref(so, &nv50->state.hw[i]);
+ so_ref(NULL, &so);
+ nv50->state.hw_dirty |= (1 << i);
+ }
nv50->dirty = 0;
- nv50_state_emit(nv50);
+
+ while (nv50->state.hw_dirty) {
+ i = ffs(nv50->state.hw_dirty) - 1;
+ nv50->state.hw_dirty &= ~(1 << i);
+
+ so_emit(chan, nv50->state.hw[i]);
+ }
return TRUE;
}