From 4da54c91d24da891c56957f29274e7821c8254f6 Mon Sep 17 00:00:00 2001 From: Christoph Bumiller Date: Sat, 6 Apr 2013 14:52:05 +0200 Subject: [PATCH] nvc0: implement multisample textures --- src/gallium/drivers/nv50/codegen/nv50_ir.h | 2 + .../nv50/codegen/nv50_ir_from_tgsi.cpp | 26 ++++++++--- src/gallium/drivers/nv50/nv50_resource.h | 1 + src/gallium/drivers/nv50/nv50_surface.c | 1 + .../nvc0/codegen/nv50_ir_lowering_nvc0.cpp | 5 +- src/gallium/drivers/nvc0/nvc0_context.c | 46 +++++++++++++++++++ src/gallium/drivers/nvc0/nvc0_miptree.c | 2 + src/gallium/drivers/nvc0/nvc0_screen.c | 2 +- src/gallium/drivers/nvc0/nvc0_surface.c | 1 + src/gallium/drivers/nvc0/nvc0_tex.c | 36 ++++++++------- 10 files changed, 97 insertions(+), 25 deletions(-) diff --git a/src/gallium/drivers/nv50/codegen/nv50_ir.h b/src/gallium/drivers/nv50/codegen/nv50_ir.h index 236673c2489..ae365af7855 100644 --- a/src/gallium/drivers/nv50/codegen/nv50_ir.h +++ b/src/gallium/drivers/nv50/codegen/nv50_ir.h @@ -824,6 +824,8 @@ public: int isArray() const { return descTable[target].array ? 1 : 0; } int isCube() const { return descTable[target].cube ? 1 : 0; } int isShadow() const { return descTable[target].shadow ? 1 : 0; } + int isMS() const { + return target == TEX_TARGET_2D_MS || target == TEX_TARGET_2D_MS_ARRAY; } Target& operator=(TexTarget targ) { diff --git a/src/gallium/drivers/nv50/codegen/nv50_ir_from_tgsi.cpp b/src/gallium/drivers/nv50/codegen/nv50_ir_from_tgsi.cpp index b546429922d..68976914240 100644 --- a/src/gallium/drivers/nv50/codegen/nv50_ir_from_tgsi.cpp +++ b/src/gallium/drivers/nv50/codegen/nv50_ir_from_tgsi.cpp @@ -358,11 +358,13 @@ static nv50_ir::TexTarget translateTexture(uint tex) switch (tex) { NV50_IR_TEX_TARG_CASE(1D, 1D); NV50_IR_TEX_TARG_CASE(2D, 2D); + NV50_IR_TEX_TARG_CASE(2D_MSAA, 2D_MS); NV50_IR_TEX_TARG_CASE(3D, 3D); NV50_IR_TEX_TARG_CASE(CUBE, CUBE); NV50_IR_TEX_TARG_CASE(RECT, RECT); NV50_IR_TEX_TARG_CASE(1D_ARRAY, 1D_ARRAY); NV50_IR_TEX_TARG_CASE(2D_ARRAY, 2D_ARRAY); + NV50_IR_TEX_TARG_CASE(2D_ARRAY_MSAA, 2D_MS_ARRAY); NV50_IR_TEX_TARG_CASE(CUBE_ARRAY, CUBE_ARRAY); NV50_IR_TEX_TARG_CASE(SHADOW1D, 1D_SHADOW); NV50_IR_TEX_TARG_CASE(SHADOW2D, 2D_SHADOW); @@ -581,6 +583,8 @@ static nv50_ir::operation translateOpcode(uint opcode) NV50_IR_OPCODE_CASE(SAMPLE_C_LZ, TEX); NV50_IR_OPCODE_CASE(SAMPLE_D, TXD); NV50_IR_OPCODE_CASE(SAMPLE_L, TXL); + NV50_IR_OPCODE_CASE(SAMPLE_I, TXF); + NV50_IR_OPCODE_CASE(SAMPLE_I_MS, TXF); NV50_IR_OPCODE_CASE(GATHER4, TXG); NV50_IR_OPCODE_CASE(SVIEWINFO, TXQ); @@ -1134,7 +1138,7 @@ private: // R,S,L,C,Dx,Dy encode TGSI sources for respective values (0xSf for auto) void setTexRS(TexInstruction *, unsigned int& s, int R, int S); void handleTEX(Value *dst0[4], int R, int S, int L, int C, int Dx, int Dy); - void handleTXF(Value *dst0[4], int R); + void handleTXF(Value *dst0[4], int R, int L_M); void handleTXQ(Value *dst0[4], enum TexQuery); void handleLIT(Value *dst0[4]); void handleUserClipPlanes(); @@ -1689,25 +1693,29 @@ Converter::handleTEX(Value *dst[4], int R, int S, int L, int C, int Dx, int Dy) bb->insertTail(texi); } -// 1st source: xyz = coordinates, w = lod +// 1st source: xyz = coordinates, w = lod/sample // 2nd source: offset void -Converter::handleTXF(Value *dst[4], int R) +Converter::handleTXF(Value *dst[4], int R, int L_M) { TexInstruction *texi = new_TexInstruction(func, tgsi.getOP()); + int ms; unsigned int c, d, s; texi->tex.target = tgsi.getTexture(code, R); + ms = texi->tex.target.isMS() ? 1 : 0; + texi->tex.levelZero = ms; /* MS textures don't have mip-maps */ + for (c = 0, d = 0; c < 4; ++c) { if (dst[c]) { texi->setDef(d++, dst[c]); texi->tex.mask |= 1 << c; } } - for (c = 0; c < texi->tex.target.getArgCount(); ++c) + for (c = 0; c < (texi->tex.target.getArgCount() - ms); ++c) texi->setSrc(c, fetchSrc(0, c)); - texi->setSrc(c++, fetchSrc(0, 3)); // lod + texi->setSrc(c++, fetchSrc(L_M >> 4, L_M & 3)); // lod or ms setTexRS(texi, c, R, -1); @@ -2392,7 +2400,13 @@ Converter::handleInstruction(const struct tgsi_full_instruction *insn) handleTEX(dst0, 1, 2, 0x30, 0x30, 0x30, 0x40); break; case TGSI_OPCODE_TXF: - handleTXF(dst0, 1); + handleTXF(dst0, 1, 0x03); + break; + case TGSI_OPCODE_SAMPLE_I: + handleTXF(dst0, 1, 0x03); + break; + case TGSI_OPCODE_SAMPLE_I_MS: + handleTXF(dst0, 1, 0x20); break; case TGSI_OPCODE_TXQ: case TGSI_OPCODE_SVIEWINFO: diff --git a/src/gallium/drivers/nv50/nv50_resource.h b/src/gallium/drivers/nv50/nv50_resource.h index 469d812098f..6b924634f7c 100644 --- a/src/gallium/drivers/nv50/nv50_resource.h +++ b/src/gallium/drivers/nv50/nv50_resource.h @@ -62,6 +62,7 @@ nv50_miptree(struct pipe_resource *pt) #define NV50_TEXVIEW_SCALED_COORDS (1 << 0) #define NV50_TEXVIEW_FILTER_MSAA8 (1 << 1) +#define NV50_TEXVIEW_ACCESS_RESOLVE (1 << 2) /* Internal functions: diff --git a/src/gallium/drivers/nv50/nv50_surface.c b/src/gallium/drivers/nv50/nv50_surface.c index 5d0b31321a0..530832f1f78 100644 --- a/src/gallium/drivers/nv50/nv50_surface.c +++ b/src/gallium/drivers/nv50/nv50_surface.c @@ -750,6 +750,7 @@ nv50_blit_set_src(struct nv50_blitctx *blit, } flags = res->last_level ? 0 : NV50_TEXVIEW_SCALED_COORDS; + flags |= NV50_TEXVIEW_ACCESS_RESOLVE; if (filter && res->nr_samples == 8) flags |= NV50_TEXVIEW_FILTER_MSAA8; diff --git a/src/gallium/drivers/nvc0/codegen/nv50_ir_lowering_nvc0.cpp b/src/gallium/drivers/nvc0/codegen/nv50_ir_lowering_nvc0.cpp index c459d60759b..4d1d37281bc 100644 --- a/src/gallium/drivers/nvc0/codegen/nv50_ir_lowering_nvc0.cpp +++ b/src/gallium/drivers/nvc0/codegen/nv50_ir_lowering_nvc0.cpp @@ -662,6 +662,7 @@ NVC0LoweringPass::handleTEX(TexInstruction *i) { const int dim = i->tex.target.getDim() + i->tex.target.isCube(); const int arg = i->tex.target.getArgCount(); + const int lyr = arg - (i->tex.target.isMS() ? 2 : 1); if (prog->getTarget()->getChipset() >= NVISA_GK104_CHIPSET) { if (i->tex.rIndirectSrc >= 0 || i->tex.sIndirectSrc >= 0) { @@ -683,7 +684,7 @@ NVC0LoweringPass::handleTEX(TexInstruction *i) } if (i->tex.target.isArray()) { LValue *layer = new_LValue(func, FILE_GPR); - Value *src = i->getSrc(arg - 1); + Value *src = i->getSrc(lyr); const int sat = (i->op == OP_TXF) ? 1 : 0; DataType sTy = (i->op == OP_TXF) ? TYPE_U32 : TYPE_F32; bld.mkCvt(OP_CVT, TYPE_U16, layer, sTy, src)->saturate = sat; @@ -696,7 +697,7 @@ NVC0LoweringPass::handleTEX(TexInstruction *i) if (dim != arg || i->tex.rIndirectSrc >= 0 || i->tex.sIndirectSrc >= 0) { LValue *src = new_LValue(func, FILE_GPR); // 0xttxsaaaa - Value *arrayIndex = i->tex.target.isArray() ? i->getSrc(arg - 1) : NULL; + Value *arrayIndex = i->tex.target.isArray() ? i->getSrc(lyr) : NULL; for (int s = dim; s >= 1; --s) i->setSrc(s, i->getSrc(s - 1)); i->setSrc(0, arrayIndex); diff --git a/src/gallium/drivers/nvc0/nvc0_context.c b/src/gallium/drivers/nvc0/nvc0_context.c index 12b890d9c0d..10baab5b335 100644 --- a/src/gallium/drivers/nvc0/nvc0_context.c +++ b/src/gallium/drivers/nvc0/nvc0_context.c @@ -214,6 +214,10 @@ nvc0_invalidate_resource_storage(struct nouveau_context *ctx, return ref; } +static void +nvc0_context_get_sample_position(struct pipe_context *, unsigned, unsigned, + float *); + struct pipe_context * nvc0_create(struct pipe_screen *pscreen, void *priv) { @@ -259,6 +263,7 @@ nvc0_create(struct pipe_screen *pscreen, void *priv) pipe->flush = nvc0_flush; pipe->texture_barrier = nvc0_texture_barrier; + pipe->get_sample_position = nvc0_context_get_sample_position; if (!screen->cur_ctx) { screen->cur_ctx = nvc0; @@ -353,3 +358,44 @@ nvc0_bufctx_fence(struct nvc0_context *nvc0, struct nouveau_bufctx *bufctx, } NOUVEAU_DRV_STAT(&nvc0->screen->base, resource_validate_count, count); } + +static void +nvc0_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: there are 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); + break; + } + xy[0] = ptr[sample_index][0] * 0.0625f; + xy[1] = ptr[sample_index][1] * 0.0625f; +} diff --git a/src/gallium/drivers/nvc0/nvc0_miptree.c b/src/gallium/drivers/nvc0/nvc0_miptree.c index 3d50735c058..ec2ab5f38f9 100644 --- a/src/gallium/drivers/nvc0/nvc0_miptree.c +++ b/src/gallium/drivers/nvc0/nvc0_miptree.c @@ -197,6 +197,8 @@ nvc0_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/nvc0/nvc0_screen.c b/src/gallium/drivers/nvc0/nvc0_screen.c index f2dd65ba0ca..ccdf2cde84b 100644 --- a/src/gallium/drivers/nvc0/nvc0_screen.c +++ b/src/gallium/drivers/nvc0/nvc0_screen.c @@ -102,6 +102,7 @@ nvc0_screen_get_param(struct pipe_screen *pscreen, enum pipe_cap param) case PIPE_CAP_SEAMLESS_CUBE_MAP: case PIPE_CAP_CUBE_MAP_ARRAY: case PIPE_CAP_TEXTURE_BUFFER_OBJECTS: + case PIPE_CAP_TEXTURE_MULTISAMPLE: return 1; case PIPE_CAP_SEAMLESS_CUBE_MAP_PER_TEXTURE: return (class_3d >= NVE4_3D_CLASS) ? 1 : 0; @@ -170,7 +171,6 @@ nvc0_screen_get_param(struct pipe_screen *pscreen, enum pipe_cap param) case PIPE_CAP_VERTEX_BUFFER_OFFSET_4BYTE_ALIGNED_ONLY: case PIPE_CAP_VERTEX_BUFFER_STRIDE_4BYTE_ALIGNED_ONLY: case PIPE_CAP_VERTEX_ELEMENT_SRC_OFFSET_4BYTE_ALIGNED_ONLY: - case PIPE_CAP_TEXTURE_MULTISAMPLE: return 0; case PIPE_CAP_COMPUTE: return (class_3d >= NVE4_3D_CLASS) ? 1 : 0; diff --git a/src/gallium/drivers/nvc0/nvc0_surface.c b/src/gallium/drivers/nvc0/nvc0_surface.c index 4e8bb36e18f..394f196241c 100644 --- a/src/gallium/drivers/nvc0/nvc0_surface.c +++ b/src/gallium/drivers/nvc0/nvc0_surface.c @@ -636,6 +636,7 @@ nvc0_blit_set_src(struct nvc0_blitctx *ctx, } flags = res->last_level ? 0 : NV50_TEXVIEW_SCALED_COORDS; + flags |= NV50_TEXVIEW_ACCESS_RESOLVE; if (filter && res->nr_samples == 8) flags |= NV50_TEXVIEW_FILTER_MSAA8; diff --git a/src/gallium/drivers/nvc0/nvc0_tex.c b/src/gallium/drivers/nvc0/nvc0_tex.c index ffd285473a9..c11d3f791fe 100644 --- a/src/gallium/drivers/nvc0/nvc0_tex.c +++ b/src/gallium/drivers/nvc0/nvc0_tex.c @@ -78,6 +78,7 @@ nvc0_create_texture_view(struct pipe_context *pipe, uint64_t address; uint32_t *tic; uint32_t swz[4]; + uint32_t width, height; uint32_t depth; struct nv50_tic_entry *view; struct nv50_miptree *mt; @@ -168,7 +169,6 @@ nvc0_create_texture_view(struct pipe_context *pipe, case PIPE_TEXTURE_1D: tic[2] |= NV50_TIC_2_TARGET_1D; break; -/* case PIPE_TEXTURE_2D_MS: */ case PIPE_TEXTURE_2D: tic[2] |= NV50_TIC_2_TARGET_2D; break; @@ -185,7 +185,6 @@ nvc0_create_texture_view(struct pipe_context *pipe, case PIPE_TEXTURE_1D_ARRAY: tic[2] |= NV50_TIC_2_TARGET_1D_ARRAY; break; -/* case PIPE_TEXTURE_2D_ARRAY_MS: */ case PIPE_TEXTURE_2D_ARRAY: tic[2] |= NV50_TIC_2_TARGET_2D_ARRAY; break; @@ -194,30 +193,35 @@ nvc0_create_texture_view(struct pipe_context *pipe, tic[2] |= NV50_TIC_2_TARGET_CUBE_ARRAY; break; default: - NOUVEAU_ERR("invalid texture target: %d\n", mt->base.base.target); + NOUVEAU_ERR("unexpected/invalid texture target: %d\n", + mt->base.base.target); return FALSE; } - if (mt->base.base.target == PIPE_BUFFER) - tic[3] = mt->base.base.width0; - else - tic[3] = (flags & NV50_TEXVIEW_FILTER_MSAA8) ? 0x20000000 : 0x00300000; + tic[3] = (flags & NV50_TEXVIEW_FILTER_MSAA8) ? 0x20000000 : 0x00300000; + + 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) | (mt->base.base.width0 << mt->ms_x); + 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 << 28; - 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; - - /* - if (mt->base.base.target == PIPE_TEXTURE_2D_MS || - mt->base.base.target == PIPE_TEXTURE_2D_ARRAY_MS) - tic[7] |= mt->ms_mode << 12; - */ + tic[7] |= mt->ms_mode << 12; return &view->pipe; } -- 2.30.2