| |
| #include "util/u_format.h" |
| |
| #include "nv50/nv50_context.h" |
| |
| static inline void |
| nv50_fb_set_null_rt(struct nouveau_pushbuf *push, unsigned i) |
| { |
| BEGIN_NV04(push, NV50_3D(RT_ADDRESS_HIGH(i)), 4); |
| PUSH_DATA (push, 0); |
| PUSH_DATA (push, 0); |
| PUSH_DATA (push, 0); |
| PUSH_DATA (push, 0); |
| BEGIN_NV04(push, NV50_3D(RT_HORIZ(i)), 2); |
| PUSH_DATA (push, 64); |
| PUSH_DATA (push, 0); |
| } |
| |
| static void |
| nv50_validate_fb(struct nv50_context *nv50) |
| { |
| struct nouveau_pushbuf *push = nv50->base.pushbuf; |
| struct pipe_framebuffer_state *fb = &nv50->framebuffer; |
| unsigned i; |
| unsigned ms_mode = NV50_3D_MULTISAMPLE_MODE_MS1; |
| uint32_t array_size = 0xffff, array_mode = 0; |
| |
| nouveau_bufctx_reset(nv50->bufctx_3d, NV50_BIND_3D_FB); |
| |
| BEGIN_NV04(push, NV50_3D(RT_CONTROL), 1); |
| PUSH_DATA (push, (076543210 << 4) | fb->nr_cbufs); |
| BEGIN_NV04(push, NV50_3D(SCREEN_SCISSOR_HORIZ), 2); |
| PUSH_DATA (push, fb->width << 16); |
| PUSH_DATA (push, fb->height << 16); |
| |
| for (i = 0; i < fb->nr_cbufs; ++i) { |
| struct nv50_miptree *mt; |
| struct nv50_surface *sf; |
| struct nouveau_bo *bo; |
| |
| if (!fb->cbufs[i]) { |
| nv50_fb_set_null_rt(push, i); |
| continue; |
| } |
| |
| mt = nv50_miptree(fb->cbufs[i]->texture); |
| sf = nv50_surface(fb->cbufs[i]); |
| bo = mt->base.bo; |
| |
| array_size = MIN2(array_size, sf->depth); |
| if (mt->layout_3d) |
| array_mode = NV50_3D_RT_ARRAY_MODE_MODE_3D; /* 1 << 16 */ |
| |
| /* can't mix 3D with ARRAY or have RTs of different depth/array_size */ |
| assert(mt->layout_3d || !array_mode || array_size == 1); |
| |
| BEGIN_NV04(push, NV50_3D(RT_ADDRESS_HIGH(i)), 5); |
| PUSH_DATAh(push, mt->base.address + sf->offset); |
| PUSH_DATA (push, mt->base.address + sf->offset); |
| PUSH_DATA (push, nv50_format_table[sf->base.format].rt); |
| if (likely(nouveau_bo_memtype(bo))) { |
| assert(sf->base.texture->target != PIPE_BUFFER); |
| |
| PUSH_DATA (push, mt->level[sf->base.u.tex.level].tile_mode); |
| PUSH_DATA (push, mt->layer_stride >> 2); |
| BEGIN_NV04(push, NV50_3D(RT_HORIZ(i)), 2); |
| PUSH_DATA (push, sf->width); |
| PUSH_DATA (push, sf->height); |
| BEGIN_NV04(push, NV50_3D(RT_ARRAY_MODE), 1); |
| PUSH_DATA (push, array_mode | array_size); |
| nv50->rt_array_mode = array_mode | array_size; |
| } else { |
| PUSH_DATA (push, 0); |
| PUSH_DATA (push, 0); |
| BEGIN_NV04(push, NV50_3D(RT_HORIZ(i)), 2); |
| PUSH_DATA (push, NV50_3D_RT_HORIZ_LINEAR | mt->level[0].pitch); |
| PUSH_DATA (push, sf->height); |
| BEGIN_NV04(push, NV50_3D(RT_ARRAY_MODE), 1); |
| PUSH_DATA (push, 0); |
| |
| assert(!fb->zsbuf); |
| assert(!mt->ms_mode); |
| } |
| |
| ms_mode = mt->ms_mode; |
| |
| if (mt->base.status & NOUVEAU_BUFFER_STATUS_GPU_READING) |
| nv50->state.rt_serialize = true; |
| mt->base.status |= NOUVEAU_BUFFER_STATUS_GPU_WRITING; |
| mt->base.status &= ~NOUVEAU_BUFFER_STATUS_GPU_READING; |
| |
| /* only register for writing, otherwise we'd always serialize here */ |
| BCTX_REFN(nv50->bufctx_3d, 3D_FB, &mt->base, WR); |
| } |
| |
| if (fb->zsbuf) { |
| struct nv50_miptree *mt = nv50_miptree(fb->zsbuf->texture); |
| struct nv50_surface *sf = nv50_surface(fb->zsbuf); |
| int unk = mt->base.base.target == PIPE_TEXTURE_3D || sf->depth == 1; |
| |
| BEGIN_NV04(push, NV50_3D(ZETA_ADDRESS_HIGH), 5); |
| PUSH_DATAh(push, mt->base.address + sf->offset); |
| PUSH_DATA (push, mt->base.address + sf->offset); |
| PUSH_DATA (push, nv50_format_table[fb->zsbuf->format].rt); |
| PUSH_DATA (push, mt->level[sf->base.u.tex.level].tile_mode); |
| PUSH_DATA (push, mt->layer_stride >> 2); |
| BEGIN_NV04(push, NV50_3D(ZETA_ENABLE), 1); |
| PUSH_DATA (push, 1); |
| BEGIN_NV04(push, NV50_3D(ZETA_HORIZ), 3); |
| PUSH_DATA (push, sf->width); |
| PUSH_DATA (push, sf->height); |
| PUSH_DATA (push, (unk << 16) | sf->depth); |
| |
| ms_mode = mt->ms_mode; |
| |
| if (mt->base.status & NOUVEAU_BUFFER_STATUS_GPU_READING) |
| nv50->state.rt_serialize = true; |
| mt->base.status |= NOUVEAU_BUFFER_STATUS_GPU_WRITING; |
| mt->base.status &= ~NOUVEAU_BUFFER_STATUS_GPU_READING; |
| |
| BCTX_REFN(nv50->bufctx_3d, 3D_FB, &mt->base, WR); |
| } else { |
| BEGIN_NV04(push, NV50_3D(ZETA_ENABLE), 1); |
| PUSH_DATA (push, 0); |
| } |
| |
| BEGIN_NV04(push, NV50_3D(MULTISAMPLE_MODE), 1); |
| PUSH_DATA (push, ms_mode); |
| |
| /* Only need to initialize the first viewport, which is used for clears */ |
| BEGIN_NV04(push, NV50_3D(VIEWPORT_HORIZ(0)), 2); |
| PUSH_DATA (push, fb->width << 16); |
| PUSH_DATA (push, fb->height << 16); |
| |
| if (nv50->screen->tesla->oclass >= NVA3_3D_CLASS) { |
| unsigned ms = 1 << ms_mode; |
| BEGIN_NV04(push, NV50_3D(CB_ADDR), 1); |
| PUSH_DATA (push, (NV50_CB_AUX_SAMPLE_OFFSET << (8 - 2)) | NV50_CB_AUX); |
| BEGIN_NI04(push, NV50_3D(CB_DATA(0)), 2 * ms); |
| for (i = 0; i < ms; i++) { |
| float xy[2]; |
| nv50->base.pipe.get_sample_position(&nv50->base.pipe, ms, i, xy); |
| PUSH_DATAf(push, xy[0]); |
| PUSH_DATAf(push, xy[1]); |
| } |
| } |
| } |
| |
| static void |
| nv50_validate_blend_colour(struct nv50_context *nv50) |
| { |
| struct nouveau_pushbuf *push = nv50->base.pushbuf; |
| |
| BEGIN_NV04(push, NV50_3D(BLEND_COLOR(0)), 4); |
| PUSH_DATAf(push, nv50->blend_colour.color[0]); |
| PUSH_DATAf(push, nv50->blend_colour.color[1]); |
| PUSH_DATAf(push, nv50->blend_colour.color[2]); |
| PUSH_DATAf(push, nv50->blend_colour.color[3]); |
| } |
| |
| static void |
| nv50_validate_stencil_ref(struct nv50_context *nv50) |
| { |
| struct nouveau_pushbuf *push = nv50->base.pushbuf; |
| |
| BEGIN_NV04(push, NV50_3D(STENCIL_FRONT_FUNC_REF), 1); |
| PUSH_DATA (push, nv50->stencil_ref.ref_value[0]); |
| BEGIN_NV04(push, NV50_3D(STENCIL_BACK_FUNC_REF), 1); |
| PUSH_DATA (push, nv50->stencil_ref.ref_value[1]); |
| } |
| |
| static void |
| nv50_validate_stipple(struct nv50_context *nv50) |
| { |
| struct nouveau_pushbuf *push = nv50->base.pushbuf; |
| unsigned i; |
| |
| BEGIN_NV04(push, NV50_3D(POLYGON_STIPPLE_PATTERN(0)), 32); |
| for (i = 0; i < 32; ++i) |
| PUSH_DATA(push, util_bswap32(nv50->stipple.stipple[i])); |
| } |
| |
| static void |
| nv50_validate_scissor(struct nv50_context *nv50) |
| { |
| struct nouveau_pushbuf *push = nv50->base.pushbuf; |
| #ifdef NV50_SCISSORS_CLIPPING |
| int minx, maxx, miny, maxy, i; |
| |
| if (!(nv50->dirty_3d & |
| (NV50_NEW_3D_SCISSOR | NV50_NEW_3D_VIEWPORT | NV50_NEW_3D_FRAMEBUFFER)) && |
| nv50->state.scissor == nv50->rast->pipe.scissor) |
| return; |
| |
| if (nv50->state.scissor != nv50->rast->pipe.scissor) |
| nv50->scissors_dirty = (1 << NV50_MAX_VIEWPORTS) - 1; |
| |
| nv50->state.scissor = nv50->rast->pipe.scissor; |
| |
| if ((nv50->dirty_3d & NV50_NEW_3D_FRAMEBUFFER) && !nv50->state.scissor) |
| nv50->scissors_dirty = (1 << NV50_MAX_VIEWPORTS) - 1; |
| |
| for (i = 0; i < NV50_MAX_VIEWPORTS; i++) { |
| struct pipe_scissor_state *s = &nv50->scissors[i]; |
| struct pipe_viewport_state *vp = &nv50->viewports[i]; |
| |
| if (!(nv50->scissors_dirty & (1 << i)) && |
| !(nv50->viewports_dirty & (1 << i))) |
| continue; |
| |
| if (nv50->state.scissor) { |
| minx = s->minx; |
| maxx = s->maxx; |
| miny = s->miny; |
| maxy = s->maxy; |
| } else { |
| minx = 0; |
| maxx = nv50->framebuffer.width; |
| miny = 0; |
| maxy = nv50->framebuffer.height; |
| } |
| |
| minx = MAX2(minx, (int)(vp->translate[0] - fabsf(vp->scale[0]))); |
| maxx = MIN2(maxx, (int)(vp->translate[0] + fabsf(vp->scale[0]))); |
| miny = MAX2(miny, (int)(vp->translate[1] - fabsf(vp->scale[1]))); |
| maxy = MIN2(maxy, (int)(vp->translate[1] + fabsf(vp->scale[1]))); |
| |
| minx = MIN2(minx, 8192); |
| maxx = MAX2(maxx, 0); |
| miny = MIN2(miny, 8192); |
| maxy = MAX2(maxy, 0); |
| |
| BEGIN_NV04(push, NV50_3D(SCISSOR_HORIZ(i)), 2); |
| PUSH_DATA (push, (maxx << 16) | minx); |
| PUSH_DATA (push, (maxy << 16) | miny); |
| #else |
| BEGIN_NV04(push, NV50_3D(SCISSOR_HORIZ(i)), 2); |
| PUSH_DATA (push, (s->maxx << 16) | s->minx); |
| PUSH_DATA (push, (s->maxy << 16) | s->miny); |
| #endif |
| } |
| |
| nv50->scissors_dirty = 0; |
| } |
| |
| static void |
| nv50_validate_viewport(struct nv50_context *nv50) |
| { |
| struct nouveau_pushbuf *push = nv50->base.pushbuf; |
| float zmin, zmax; |
| int i; |
| |
| for (i = 0; i < NV50_MAX_VIEWPORTS; i++) { |
| struct pipe_viewport_state *vpt = &nv50->viewports[i]; |
| |
| if (!(nv50->viewports_dirty & (1 << i))) |
| continue; |
| |
| BEGIN_NV04(push, NV50_3D(VIEWPORT_TRANSLATE_X(i)), 3); |
| PUSH_DATAf(push, vpt->translate[0]); |
| PUSH_DATAf(push, vpt->translate[1]); |
| PUSH_DATAf(push, vpt->translate[2]); |
| BEGIN_NV04(push, NV50_3D(VIEWPORT_SCALE_X(i)), 3); |
| PUSH_DATAf(push, vpt->scale[0]); |
| PUSH_DATAf(push, vpt->scale[1]); |
| PUSH_DATAf(push, vpt->scale[2]); |
| |
| zmin = vpt->translate[2] - fabsf(vpt->scale[2]); |
| zmax = vpt->translate[2] + fabsf(vpt->scale[2]); |
| |
| #ifdef NV50_SCISSORS_CLIPPING |
| BEGIN_NV04(push, NV50_3D(DEPTH_RANGE_NEAR(i)), 2); |
| PUSH_DATAf(push, zmin); |
| PUSH_DATAf(push, zmax); |
| #endif |
| } |
| |
| nv50->viewports_dirty = 0; |
| } |
| |
| static void |
| nv50_validate_window_rects(struct nv50_context *nv50) |
| { |
| struct nouveau_pushbuf *push = nv50->base.pushbuf; |
| bool enable = nv50->window_rect.rects > 0 || nv50->window_rect.inclusive; |
| int i; |
| |
| BEGIN_NV04(push, NV50_3D(CLIP_RECTS_EN), 1); |
| PUSH_DATA (push, enable); |
| if (!enable) |
| return; |
| |
| BEGIN_NV04(push, NV50_3D(CLIP_RECTS_MODE), 1); |
| PUSH_DATA (push, !nv50->window_rect.inclusive); |
| BEGIN_NV04(push, NV50_3D(CLIP_RECT_HORIZ(0)), NV50_MAX_WINDOW_RECTANGLES * 2); |
| for (i = 0; i < nv50->window_rect.rects; i++) { |
| struct pipe_scissor_state *s = &nv50->window_rect.rect[i]; |
| PUSH_DATA(push, (s->maxx << 16) | s->minx); |
| PUSH_DATA(push, (s->maxy << 16) | s->miny); |
| } |
| for (; i < NV50_MAX_WINDOW_RECTANGLES; i++) { |
| PUSH_DATA(push, 0); |
| PUSH_DATA(push, 0); |
| } |
| } |
| |
| static inline void |
| nv50_check_program_ucps(struct nv50_context *nv50, |
| struct nv50_program *vp, uint8_t mask) |
| { |
| const unsigned n = util_logbase2(mask) + 1; |
| |
| if (vp->vp.clpd_nr >= n) |
| return; |
| nv50_program_destroy(nv50, vp); |
| |
| vp->vp.clpd_nr = n; |
| if (likely(vp == nv50->vertprog)) { |
| nv50->dirty_3d |= NV50_NEW_3D_VERTPROG; |
| nv50_vertprog_validate(nv50); |
| } else { |
| nv50->dirty_3d |= NV50_NEW_3D_GMTYPROG; |
| nv50_gmtyprog_validate(nv50); |
| } |
| nv50_fp_linkage_validate(nv50); |
| } |
| |
| /* alpha test is disabled if there are no color RTs, so make sure we have at |
| * least one if alpha test is enabled. Note that this must run after |
| * nv50_validate_fb, otherwise that will override the RT count setting. |
| */ |
| static void |
| nv50_validate_derived_2(struct nv50_context *nv50) |
| { |
| struct nouveau_pushbuf *push = nv50->base.pushbuf; |
| |
| if (nv50->zsa && nv50->zsa->pipe.alpha.enabled && |
| nv50->framebuffer.nr_cbufs == 0) { |
| nv50_fb_set_null_rt(push, 0); |
| BEGIN_NV04(push, NV50_3D(RT_CONTROL), 1); |
| PUSH_DATA (push, (076543210 << 4) | 1); |
| } |
| } |
| |
| static void |
| nv50_validate_derived_3(struct nv50_context *nv50) |
| { |
| struct nouveau_pushbuf *push = nv50->base.pushbuf; |
| struct pipe_framebuffer_state *fb = &nv50->framebuffer; |
| uint32_t ms = 0; |
| |
| if ((!fb->nr_cbufs || !fb->cbufs[0] || |
| !util_format_is_pure_integer(fb->cbufs[0]->format)) && nv50->blend) { |
| if (nv50->blend->pipe.alpha_to_coverage) |
| ms |= NV50_3D_MULTISAMPLE_CTRL_ALPHA_TO_COVERAGE; |
| if (nv50->blend->pipe.alpha_to_one) |
| ms |= NV50_3D_MULTISAMPLE_CTRL_ALPHA_TO_ONE; |
| } |
| |
| BEGIN_NV04(push, NV50_3D(MULTISAMPLE_CTRL), 1); |
| PUSH_DATA (push, ms); |
| } |
| |
| static void |
| nv50_validate_clip(struct nv50_context *nv50) |
| { |
| struct nouveau_pushbuf *push = nv50->base.pushbuf; |
| struct nv50_program *vp; |
| uint8_t clip_enable = nv50->rast->pipe.clip_plane_enable; |
| |
| if (nv50->dirty_3d & NV50_NEW_3D_CLIP) { |
| BEGIN_NV04(push, NV50_3D(CB_ADDR), 1); |
| PUSH_DATA (push, (NV50_CB_AUX_UCP_OFFSET << 8) | NV50_CB_AUX); |
| BEGIN_NI04(push, NV50_3D(CB_DATA(0)), PIPE_MAX_CLIP_PLANES * 4); |
| PUSH_DATAp(push, &nv50->clip.ucp[0][0], PIPE_MAX_CLIP_PLANES * 4); |
| } |
| |
| vp = nv50->gmtyprog; |
| if (likely(!vp)) |
| vp = nv50->vertprog; |
| |
| if (clip_enable) |
| nv50_check_program_ucps(nv50, vp, clip_enable); |
| |
| clip_enable &= vp->vp.clip_enable; |
| clip_enable |= vp->vp.cull_enable; |
| |
| BEGIN_NV04(push, NV50_3D(CLIP_DISTANCE_ENABLE), 1); |
| PUSH_DATA (push, clip_enable); |
| |
| if (nv50->state.clip_mode != vp->vp.clip_mode) { |
| nv50->state.clip_mode = vp->vp.clip_mode; |
| BEGIN_NV04(push, NV50_3D(CLIP_DISTANCE_MODE), 1); |
| PUSH_DATA (push, vp->vp.clip_mode); |
| } |
| } |
| |
| static void |
| nv50_validate_blend(struct nv50_context *nv50) |
| { |
| struct nouveau_pushbuf *push = nv50->base.pushbuf; |
| |
| PUSH_SPACE(push, nv50->blend->size); |
| PUSH_DATAp(push, nv50->blend->state, nv50->blend->size); |
| } |
| |
| static void |
| nv50_validate_zsa(struct nv50_context *nv50) |
| { |
| struct nouveau_pushbuf *push = nv50->base.pushbuf; |
| |
| PUSH_SPACE(push, nv50->zsa->size); |
| PUSH_DATAp(push, nv50->zsa->state, nv50->zsa->size); |
| } |
| |
| static void |
| nv50_validate_rasterizer(struct nv50_context *nv50) |
| { |
| struct nouveau_pushbuf *push = nv50->base.pushbuf; |
| |
| PUSH_SPACE(push, nv50->rast->size); |
| PUSH_DATAp(push, nv50->rast->state, nv50->rast->size); |
| } |
| |
| static void |
| nv50_validate_sample_mask(struct nv50_context *nv50) |
| { |
| struct nouveau_pushbuf *push = nv50->base.pushbuf; |
| |
| unsigned mask[4] = |
| { |
| nv50->sample_mask & 0xffff, |
| nv50->sample_mask & 0xffff, |
| nv50->sample_mask & 0xffff, |
| nv50->sample_mask & 0xffff |
| }; |
| |
| BEGIN_NV04(push, NV50_3D(MSAA_MASK(0)), 4); |
| PUSH_DATA (push, mask[0]); |
| PUSH_DATA (push, mask[1]); |
| PUSH_DATA (push, mask[2]); |
| PUSH_DATA (push, mask[3]); |
| } |
| |
| static void |
| nv50_validate_min_samples(struct nv50_context *nv50) |
| { |
| struct nouveau_pushbuf *push = nv50->base.pushbuf; |
| int samples; |
| |
| if (nv50->screen->tesla->oclass < NVA3_3D_CLASS) |
| return; |
| |
| samples = util_next_power_of_two(nv50->min_samples); |
| if (samples > 1) |
| samples |= NVA3_3D_SAMPLE_SHADING_ENABLE; |
| |
| BEGIN_NV04(push, SUBC_3D(NVA3_3D_SAMPLE_SHADING), 1); |
| PUSH_DATA (push, samples); |
| } |
| |
| static void |
| nv50_switch_pipe_context(struct nv50_context *ctx_to) |
| { |
| struct nv50_context *ctx_from = ctx_to->screen->cur_ctx; |
| |
| if (ctx_from) |
| ctx_to->state = ctx_from->state; |
| else |
| ctx_to->state = ctx_to->screen->save_state; |
| |
| ctx_to->dirty_3d = ~0; |
| ctx_to->dirty_cp = ~0; |
| ctx_to->viewports_dirty = ~0; |
| ctx_to->scissors_dirty = ~0; |
| |
| ctx_to->constbuf_dirty[0] = |
| ctx_to->constbuf_dirty[1] = |
| ctx_to->constbuf_dirty[2] = (1 << NV50_MAX_PIPE_CONSTBUFS) - 1; |
| |
| if (!ctx_to->vertex) |
| ctx_to->dirty_3d &= ~(NV50_NEW_3D_VERTEX | NV50_NEW_3D_ARRAYS); |
| |
| if (!ctx_to->vertprog) |
| ctx_to->dirty_3d &= ~NV50_NEW_3D_VERTPROG; |
| if (!ctx_to->fragprog) |
| ctx_to->dirty_3d &= ~NV50_NEW_3D_FRAGPROG; |
| |
| if (!ctx_to->blend) |
| ctx_to->dirty_3d &= ~NV50_NEW_3D_BLEND; |
| if (!ctx_to->rast) |
| #ifdef NV50_SCISSORS_CLIPPING |
| ctx_to->dirty_3d &= ~(NV50_NEW_3D_RASTERIZER | NV50_NEW_3D_SCISSOR); |
| #else |
| ctx_to->dirty_3d &= ~NV50_NEW_3D_RASTERIZER; |
| #endif |
| if (!ctx_to->zsa) |
| ctx_to->dirty_3d &= ~NV50_NEW_3D_ZSA; |
| |
| ctx_to->screen->cur_ctx = ctx_to; |
| } |
| |
| static struct nv50_state_validate |
| validate_list_3d[] = { |
| { nv50_validate_fb, NV50_NEW_3D_FRAMEBUFFER }, |
| { nv50_validate_blend, NV50_NEW_3D_BLEND }, |
| { nv50_validate_zsa, NV50_NEW_3D_ZSA }, |
| { nv50_validate_sample_mask, NV50_NEW_3D_SAMPLE_MASK }, |
| { nv50_validate_rasterizer, NV50_NEW_3D_RASTERIZER }, |
| { nv50_validate_blend_colour, NV50_NEW_3D_BLEND_COLOUR }, |
| { nv50_validate_stencil_ref, NV50_NEW_3D_STENCIL_REF }, |
| { nv50_validate_stipple, NV50_NEW_3D_STIPPLE }, |
| #ifdef NV50_SCISSORS_CLIPPING |
| { nv50_validate_scissor, NV50_NEW_3D_SCISSOR | NV50_NEW_3D_VIEWPORT | |
| NV50_NEW_3D_RASTERIZER | |
| NV50_NEW_3D_FRAMEBUFFER }, |
| #else |
| { nv50_validate_scissor, NV50_NEW_3D_SCISSOR }, |
| #endif |
| { nv50_validate_viewport, NV50_NEW_3D_VIEWPORT }, |
| { nv50_validate_window_rects, NV50_NEW_3D_WINDOW_RECTS }, |
| { nv50_vertprog_validate, NV50_NEW_3D_VERTPROG }, |
| { nv50_gmtyprog_validate, NV50_NEW_3D_GMTYPROG }, |
| { nv50_fragprog_validate, NV50_NEW_3D_FRAGPROG | NV50_NEW_3D_RASTERIZER | |
| NV50_NEW_3D_MIN_SAMPLES }, |
| { nv50_fp_linkage_validate, NV50_NEW_3D_FRAGPROG | NV50_NEW_3D_VERTPROG | |
| NV50_NEW_3D_GMTYPROG | NV50_NEW_3D_RASTERIZER }, |
| { nv50_gp_linkage_validate, NV50_NEW_3D_GMTYPROG | NV50_NEW_3D_VERTPROG }, |
| { nv50_validate_derived_rs, NV50_NEW_3D_FRAGPROG | NV50_NEW_3D_RASTERIZER | |
| NV50_NEW_3D_VERTPROG | NV50_NEW_3D_GMTYPROG }, |
| { nv50_validate_derived_2, NV50_NEW_3D_ZSA | NV50_NEW_3D_FRAMEBUFFER }, |
| { nv50_validate_derived_3, NV50_NEW_3D_BLEND | NV50_NEW_3D_FRAMEBUFFER }, |
| { nv50_validate_clip, NV50_NEW_3D_CLIP | NV50_NEW_3D_RASTERIZER | |
| NV50_NEW_3D_VERTPROG | NV50_NEW_3D_GMTYPROG }, |
| { nv50_constbufs_validate, NV50_NEW_3D_CONSTBUF }, |
| { nv50_validate_textures, NV50_NEW_3D_TEXTURES }, |
| { nv50_validate_samplers, NV50_NEW_3D_SAMPLERS }, |
| { nv50_stream_output_validate, NV50_NEW_3D_STRMOUT | |
| NV50_NEW_3D_VERTPROG | NV50_NEW_3D_GMTYPROG }, |
| { nv50_vertex_arrays_validate, NV50_NEW_3D_VERTEX | NV50_NEW_3D_ARRAYS }, |
| { nv50_validate_min_samples, NV50_NEW_3D_MIN_SAMPLES }, |
| }; |
| |
| bool |
| nv50_state_validate(struct nv50_context *nv50, uint32_t mask, |
| struct nv50_state_validate *validate_list, int size, |
| uint32_t *dirty, struct nouveau_bufctx *bufctx) |
| { |
| uint32_t state_mask; |
| int ret; |
| unsigned i; |
| |
| if (nv50->screen->cur_ctx != nv50) |
| nv50_switch_pipe_context(nv50); |
| |
| state_mask = *dirty & mask; |
| |
| if (state_mask) { |
| for (i = 0; i < size; i++) { |
| struct nv50_state_validate *validate = &validate_list[i]; |
| |
| if (state_mask & validate->states) |
| validate->func(nv50); |
| } |
| *dirty &= ~state_mask; |
| |
| if (nv50->state.rt_serialize) { |
| nv50->state.rt_serialize = false; |
| BEGIN_NV04(nv50->base.pushbuf, SUBC_3D(NV50_GRAPH_SERIALIZE), 1); |
| PUSH_DATA (nv50->base.pushbuf, 0); |
| } |
| |
| nv50_bufctx_fence(bufctx, false); |
| } |
| nouveau_pushbuf_bufctx(nv50->base.pushbuf, bufctx); |
| ret = nouveau_pushbuf_validate(nv50->base.pushbuf); |
| |
| return !ret; |
| } |
| |
| bool |
| nv50_state_validate_3d(struct nv50_context *nv50, uint32_t mask) |
| { |
| bool ret; |
| |
| ret = nv50_state_validate(nv50, mask, validate_list_3d, |
| ARRAY_SIZE(validate_list_3d), &nv50->dirty_3d, |
| nv50->bufctx_3d); |
| |
| if (unlikely(nv50->state.flushed)) { |
| nv50->state.flushed = false; |
| nv50_bufctx_fence(nv50->bufctx_3d, true); |
| } |
| return ret; |
| } |