[Mesa-dev] [PATCH] nv50: implement multisample textures

This is a port of 4da54c91d24da ("nvc0: implement multisample textures") to nv50. When coupled with the patch to only report 16 texture samplers (to fix crashes), all of the Piglit tests in spec/arb_texture_multisample pass. --- .../nouveau/codegen/nv50_ir_lowering_nv50.cpp | 5 ++- src/gallium/drivers/nouveau/nv50/nv50_context.c | 46 ++++++++++++++++++++ src/gallium/drivers/nouveau/nv50/nv50_miptree.c | 2 + src/gallium/drivers/nouveau/nv50/nv50_screen.c | 3 +- src/gallium/drivers/nouveau/nv50/nv50_tex.c | 20 +++++++-- 5 files changed, 70 insertions(+), 6 deletions(-) diff --git a/src/gallium/drivers/nouveau/codegen/nv50_ir_lowering_nv50.cpp b/src/gallium/drivers/nouveau/codegen/nv50_ir_lowering_nv50.cpp index caaf09f..d5d1f1e 100644 --- a/src/gallium/drivers/nouveau/codegen/nv50_ir_lowering_nv50.cpp +++ b/src/gallium/drivers/nouveau/codegen/nv50_ir_lowering_nv50.cpp @@ -569,6 +569,7 @@ NV50LoweringPreSSA::handleTEX(TexInstruction *i) const int arg = i->tex.target.getArgCount(); const int dref = arg; const int lod = i->tex.target.isShadow() ? (arg + 1) : arg; + const int lyr = arg - (i->tex.target.isMS() ? 2 : 1); // dref comes before bias/lod if (i->tex.target.isShadow()) @@ -577,11 +578,11 @@ NV50LoweringPreSSA::handleTEX(TexInstruction *i) // array index must be converted to u32 if (i->tex.target.isArray()) { - Value *layer = i->getSrc(arg - 1); + Value *layer = i->getSrc(lyr); LValue *src = new_LValue(func, FILE_GPR); bld.mkCvt(OP_CVT, TYPE_U32, src, TYPE_F32, layer); bld.mkOp2(OP_MIN, TYPE_U32, src, src, bld.loadImm(NULL, 511)); - i->setSrc(arg - 1, src); + i->setSrc(lyr, src); if (i->tex.target.isCube()) { std::vector<Value *> acube, a2d; diff --git a/src/gallium/drivers/nouveau/nv50/nv50_context.c b/src/gallium/drivers/nouveau/nv50/nv50_context.c index b6bdf79..45e3f5d 100644 --- a/src/gallium/drivers/nouveau/nv50/nv50_context.c +++ b/src/gallium/drivers/nouveau/nv50/nv50_context.c @@ -194,6 +194,10 @@ nv50_invalidate_resource_storage(struct nouveau_context *ctx, return ref; } +static void +nv50_context_get_sample_position(struct pipe_context *, unsigned, unsigned, + float *); + struct pipe_context * nv50_create(struct pipe_screen *pscreen, void *priv) { @@ -237,6 +241,7 @@ nv50_create(struct pipe_screen *pscreen, void *priv) pipe->flush = nv50_flush; pipe->texture_barrier = nv50_texture_barrier; + pipe->get_sample_position = nv50_context_get_sample_position; if (!screen->cur_ctx) { screen->cur_ctx = nv50; @@ -315,3 +320,44 @@ nv50_bufctx_fence(struct nouveau_bufctx *bufctx, boolean on_flush) nv50_resource_validate(res, (unsigned)ref->priv_data); } } + +static void +nv50_context_get_sample_position(struct pipe_context *pipe, + unsigned sample_count, unsigned sample_index, + float *xy) +{ + static const uint8_t ms1[1][2] = { { 0x8, 0x8 } }; + static const uint8_t ms2[2][2] = { + { 0x4, 0x4 }, { 0xc, 0xc } }; /* surface coords (0,0), (1,0) */ + static const uint8_t ms4[4][2] = { + { 0x6, 0x2 }, { 0xe, 0x6 }, /* (0,0), (1,0) */ + { 0x2, 0xa }, { 0xa, 0xe } }; /* (0,1), (1,1) */ + static const uint8_t ms8[8][2] = { + { 0x1, 0x7 }, { 0x5, 0x3 }, /* (0,0), (1,0) */ + { 0x3, 0xd }, { 0x7, 0xb }, /* (0,1), (1,1) */ + { 0x9, 0x5 }, { 0xf, 0x1 }, /* (2,0), (3,0) */ + { 0xb, 0xf }, { 0xd, 0x9 } }; /* (2,1), (3,1) */ +#if 0 + /* NOTE: NVA3+ has alternative modes for MS2 and MS8, currently not used */ + static const uint8_t ms8_alt[8][2] = { + { 0x9, 0x5 }, { 0x7, 0xb }, /* (2,0), (1,1) */ + { 0xd, 0x9 }, { 0x5, 0x3 }, /* (3,1), (1,0) */ + { 0x3, 0xd }, { 0x1, 0x7 }, /* (0,1), (0,0) */ + { 0xb, 0xf }, { 0xf, 0x1 } }; /* (2,1), (3,0) */ +#endif + + const uint8_t (*ptr)[2]; + + switch (sample_count) { + case 0: + case 1: ptr = ms1; break; + case 2: ptr = ms2; break; + case 4: ptr = ms4; break; + case 8: ptr = ms8; break; + default: + assert(0); + return; /* bad sample count -> undefined locations */ + } + xy[0] = ptr[sample_index][0] * 0.0625f; + xy[1] = ptr[sample_index][1] * 0.0625f; +} diff --git a/src/gallium/drivers/nouveau/nv50/nv50_miptree.c b/src/gallium/drivers/nouveau/nv50/nv50_miptree.c index 513d8f9..1963a4a 100644 --- a/src/gallium/drivers/nouveau/nv50/nv50_miptree.c +++ b/src/gallium/drivers/nouveau/nv50/nv50_miptree.c @@ -277,6 +277,8 @@ nv50_miptree_init_layout_tiled(struct nv50_miptree *mt) */ d = mt->layout_3d ? pt->depth0 : 1; + assert(!mt->ms_mode || !pt->last_level); + for (l = 0; l <= pt->last_level; ++l) { struct nv50_miptree_level *lvl = &mt->level[l]; unsigned tsx, tsy, tsz; diff --git a/src/gallium/drivers/nouveau/nv50/nv50_screen.c b/src/gallium/drivers/nouveau/nv50/nv50_screen.c index f454ec7..47cf1a1 100644 --- a/src/gallium/drivers/nouveau/nv50/nv50_screen.c +++ b/src/gallium/drivers/nouveau/nv50/nv50_screen.c @@ -183,8 +183,9 @@ nv50_screen_get_param(struct pipe_screen *pscreen, enum pipe_cap param) case PIPE_CAP_VERTEX_BUFFER_STRIDE_4BYTE_ALIGNED_ONLY: case PIPE_CAP_VERTEX_ELEMENT_SRC_OFFSET_4BYTE_ALIGNED_ONLY: case PIPE_CAP_TGSI_TEXCOORD: - case PIPE_CAP_TEXTURE_MULTISAMPLE: return 0; + case PIPE_CAP_TEXTURE_MULTISAMPLE: + return 1; case PIPE_CAP_PREFER_BLIT_BASED_TEXTURE_TRANSFER: return 1; case PIPE_CAP_QUERY_PIPELINE_STATISTICS: diff --git a/src/gallium/drivers/nouveau/nv50/nv50_tex.c b/src/gallium/drivers/nouveau/nv50/nv50_tex.c index 9e51292..40af224 100644 --- a/src/gallium/drivers/nouveau/nv50/nv50_tex.c +++ b/src/gallium/drivers/nouveau/nv50/nv50_tex.c @@ -75,6 +75,7 @@ nv50_create_texture_view(struct pipe_context *pipe, uint64_t addr; uint32_t *tic; uint32_t swz[4]; + uint32_t width, height; uint32_t depth; struct nv50_tic_entry *view; struct nv50_miptree *mt = nv50_miptree(texture); @@ -197,15 +198,28 @@ nv50_create_texture_view(struct pipe_context *pipe, tic[3] = (flags & NV50_TEXVIEW_FILTER_MSAA8) ? 0x20000000 : 0x00300000; - tic[4] = (1 << 31) | (mt->base.base.width0 << mt->ms_x); + if (flags & NV50_TEXVIEW_ACCESS_RESOLVE) { + width = mt->base.base.width0 << mt->ms_x; + height = mt->base.base.height0 << mt->ms_y; + } else { + width = mt->base.base.width0; + height = mt->base.base.height0; + } + + tic[4] = (1 << 31) | width; - tic[5] = (mt->base.base.height0 << mt->ms_y) & 0xffff; + tic[5] = height & 0xffff; tic[5] |= depth << 16; tic[5] |= mt->base.base.last_level << NV50_TIC_5_LAST_LEVEL__SHIFT; - tic[6] = (mt->ms_x > 1) ? 0x88000000 : 0x03000000; /* sampling points */ + /* sampling points: (?) */ + if (flags & NV50_TEXVIEW_ACCESS_RESOLVE) + tic[6] = (mt->ms_x > 1) ? 0x88000000 : 0x03000000; + else + tic[6] = 0x03000000; tic[7] = (view->pipe.u.tex.last_level << 4) | view->pipe.u.tex.first_level; + tic[7] |= mt->ms_mode << 12; if (unlikely(!(tic[2] & NV50_TIC_2_NORMALIZED_COORDS))) if (mt->base.base.last_level) -- 1.7.9.5