diff options
author | Christoph Bumiller <[email protected]> | 2011-09-14 18:30:37 +0200 |
---|---|---|
committer | Christoph Bumiller <[email protected]> | 2011-09-14 18:30:53 +0200 |
commit | 7744e867b7f45f3f9d763b61d7219dc28ca39c45 (patch) | |
tree | c465b6423fd6b54f268b00146383f989e10a106e /src/gallium/drivers/nvc0/nvc0_surface.c | |
parent | 9cae933f4abcad46d8a965b34aa79801663e0818 (diff) |
nvc0: implement resource_resolve
Diffstat (limited to 'src/gallium/drivers/nvc0/nvc0_surface.c')
-rw-r--r-- | src/gallium/drivers/nvc0/nvc0_surface.c | 515 |
1 files changed, 514 insertions, 1 deletions
diff --git a/src/gallium/drivers/nvc0/nvc0_surface.c b/src/gallium/drivers/nvc0/nvc0_surface.c index 385e2f0268b..61aa1a17f1d 100644 --- a/src/gallium/drivers/nvc0/nvc0_surface.c +++ b/src/gallium/drivers/nvc0/nvc0_surface.c @@ -421,14 +421,527 @@ nvc0_clear(struct pipe_context *pipe, unsigned buffers, } } + +struct nvc0_blitctx +{ + struct nvc0_screen *screen; + struct { + struct pipe_framebuffer_state fb; + struct nvc0_program *vp; + struct nvc0_program *tcp; + struct nvc0_program *tep; + struct nvc0_program *gp; + struct nvc0_program *fp; + unsigned num_textures[5]; + unsigned num_samplers[5]; + struct pipe_sampler_view *texture; + struct nv50_tsc_entry *sampler; + unsigned dirty; + unsigned clip_nr; + } saved; + struct nvc0_program vp; + struct nvc0_program fp; + struct nv50_tsc_entry sampler[2]; /* nearest, bilinear */ + uint32_t fp_offset; + uint16_t color_mask; + uint8_t filter; +}; + +static void +nvc0_blitctx_make_vp(struct nvc0_blitctx *blit) +{ + static const uint32_t code[] = + { + 0xfff01c66, 0x06000080, /* vfetch b128 { $r0 $r1 $r2 $r3 } a[0x80] */ + 0xfff11c26, 0x06000090, /* vfetch b64 { $r4 $r5 } a[0x90]*/ + 0x03f01c66, 0x0a7e0070, /* export b128 o[0x70] { $r0 $r1 $r2 $r3 } */ + 0x13f01c26, 0x0a7e0080, /* export b64 o[0x80] { $r4 $r5 } */ + 0x00001de7, 0x80000000, /* exit */ + }; + + blit->vp.type = PIPE_SHADER_VERTEX; + blit->vp.translated = TRUE; + blit->vp.code = (uint32_t *)code; /* no relocations -> no modification */ + blit->vp.code_size = sizeof(code); + blit->vp.max_gpr = 6; + blit->vp.vp.edgeflag = PIPE_MAX_ATTRIBS; + + blit->vp.hdr[0] = 0x00020461; /* vertprog magic */ + blit->vp.hdr[4] = 0x000ff000; /* no outputs read */ + blit->vp.hdr[6] = 0x0000003f; /* a[0x80], a[0x90] */ + blit->vp.hdr[13] = 0x0003f000; /* o[0x70], o[0x80] */ +} + +static void +nvc0_blitctx_make_fp(struct nvc0_blitctx *blit) +{ + static const uint32_t code[] = /* use nvc0dis */ + { + /* 2 coords RGBA in, RGBA out, also for Z32_FLOAT(_S8X24_USCALED) + * NOTE: + * NVC0 doesn't like tex 3d on non-3d textures, but there should + * only be 2d and 2d-array MS resources anyway. + */ + 0xfff01c00, 0xc07e0080, + 0xfff05c00, 0xc07e0084, + 0x00001c86, 0x8013c000, + 0x00001de7, 0x80000000, + /* size: 0x70 + padding */ + 0, 0, 0, 0, + + /* 2 coords ZS in, S encoded in R, Z encoded in GBA (8_UNORM) + * Setup float outputs in a way that conversion to UNORM yields the + * desired byte value. + */ + /* NOTE: need to repeat header */ + 0x00021462, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x80000000, 0x0000000f, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x0000000f, 0x00000000, + 0xfff01c00, 0xc07e0080, + 0xfff05c00, 0xc07e0084, + 0x00001c86, 0x8010c000, + 0xfc009c02, 0x312dffff, + 0x05001c88, + 0x09009e88, + 0x04001c02, 0x30ee0202, + 0xfc205c02, 0x38000003, + 0x0020dc02, 0x3803fc00, + 0x00209c02, 0x380003fc, + 0x05005c88, + 0x0d00dc88, + 0x09209e04, 0x18000000, + 0x04105c02, 0x30ee0202, + 0x0430dc02, 0x30ce0202, + 0x04209c02, 0x30de0202, + 0x00001de7, 0x80000000, + /* size: 0xc8 + padding */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + /* 2 coords ZS in, Z encoded in RGB, S encoded in A (U8_UNORM) */ + 0x00021462, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x80000000, 0x0000000f, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x0000000f, 0x00000000, + 0xfff01c00, 0xc07e0080, + 0xfff05c00, 0xc07e0084, + 0x00001c86, 0x8010c000, + 0xfc009c02, 0x312dffff, + 0x05081c88, + 0x09009e88, + 0x0430dc02, 0x30ee0202, + 0xfc201c02, 0x38000003, + 0x00205c02, 0x380003fc, + 0x00209c02, 0x3803fc00, + 0x01001c88, + 0x05005c88, + 0x09209e04, 0x18000000, + 0x04001c02, 0x30ee0202, + 0x04105c02, 0x30de0202, + 0x04209c02, 0x30ce0202, + 0x00001de7, 0x80000000, + }; + + blit->fp.type = PIPE_SHADER_FRAGMENT; + blit->fp.translated = TRUE; + blit->fp.code = (uint32_t *)code; /* const_cast */ + blit->fp.code_size = sizeof(code); + blit->fp.max_gpr = 4; + + blit->fp.hdr[0] = 0x00021462; /* fragprog magic */ + blit->fp.hdr[5] = 0x80000000; + blit->fp.hdr[6] = 0x0000000f; /* 2 linear */ + blit->fp.hdr[18] = 0x0000000f; /* 1 colour output */ +} + +static void +nvc0_blitctx_make_sampler(struct nvc0_blitctx *blit) +{ + /* clamp to edge, min/max lod = 0, nearest filtering */ + + blit->sampler[0].id = -1; + + blit->sampler[0].tsc[0] = 0x00000092; + blit->sampler[0].tsc[1] = 0x00000051; + + /* clamp to edge, min/max lod = 0, bilinear filtering */ + + blit->sampler[1].id = -1; + + blit->sampler[1].tsc[0] = 0x00000092; + blit->sampler[1].tsc[1] = 0x00000062; +} + +/* Since shaders cannot export stencil, we cannot copy stencil values when + * rendering to ZETA, so we attach the ZS surface to a colour render target. + */ +static INLINE enum pipe_format +nvc0_blit_zeta_to_colour_format(enum pipe_format format) +{ + switch (format) { + case PIPE_FORMAT_Z16_UNORM: return PIPE_FORMAT_R16_UNORM; + case PIPE_FORMAT_Z24_UNORM_S8_USCALED: + case PIPE_FORMAT_S8_USCALED_Z24_UNORM: + case PIPE_FORMAT_Z24X8_UNORM: return PIPE_FORMAT_R8G8B8A8_UNORM; + case PIPE_FORMAT_Z32_FLOAT: return PIPE_FORMAT_R32_FLOAT; + case PIPE_FORMAT_Z32_FLOAT_S8X24_USCALED: return PIPE_FORMAT_R32G32_FLOAT; + default: + assert(0); + return PIPE_FORMAT_NONE; + } +} + +static void +nvc0_blitctx_get_color_mask_and_fp(struct nvc0_blitctx *blit, + enum pipe_format format, uint8_t mask) +{ + blit->color_mask = 0; + + switch (format) { + case PIPE_FORMAT_Z24X8_UNORM: + case PIPE_FORMAT_Z24_UNORM_S8_USCALED: + blit->fp_offset = 0x180; + if (mask & PIPE_MASK_Z) + blit->color_mask |= 0x0111; + if (mask & PIPE_MASK_S) + blit->color_mask |= 0x1000; + break; + case PIPE_FORMAT_S8_USCALED_Z24_UNORM: + blit->fp_offset = 0x80; + if (mask & PIPE_MASK_Z) + blit->color_mask |= 0x1110; + if (mask & PIPE_MASK_S) + blit->color_mask |= 0x0001; + break; + default: + blit->fp_offset = 0; + if (mask & (PIPE_MASK_R | PIPE_MASK_Z)) blit->color_mask |= 0x0001; + if (mask & (PIPE_MASK_G | PIPE_MASK_S)) blit->color_mask |= 0x0010; + if (mask & PIPE_MASK_B) blit->color_mask |= 0x0100; + if (mask & PIPE_MASK_A) blit->color_mask |= 0x1000; + break; + } +} + +static void +nvc0_blit_set_dst(struct nvc0_context *nvc0, + struct pipe_resource *res, unsigned level, unsigned layer) +{ + struct pipe_context *pipe = &nvc0->base.pipe; + struct pipe_surface templ; + + if (util_format_is_depth_or_stencil(res->format)) + templ.format = nvc0_blit_zeta_to_colour_format(res->format); + else + templ.format = res->format; + + templ.usage = PIPE_USAGE_STREAM; + templ.u.tex.level = level; + templ.u.tex.first_layer = templ.u.tex.last_layer = layer; + + nvc0->framebuffer.cbufs[0] = nvc0_miptree_surface_new(pipe, res, &templ); + nvc0->framebuffer.nr_cbufs = 1; + nvc0->framebuffer.zsbuf = NULL; + nvc0->framebuffer.width = nvc0->framebuffer.cbufs[0]->width; + nvc0->framebuffer.height = nvc0->framebuffer.cbufs[0]->height; +} + +static INLINE void +nvc0_blit_fixup_tic_entry(struct pipe_sampler_view *view) +{ + struct nv50_tic_entry *ent = nv50_tic_entry(view); + + ent->tic[2] &= ~(1 << 31); /* scaled coordinates, ok with 3d textures ? */ + + /* magic: */ + + ent->tic[3] = 0x20000000; /* affects quality of near vertical edges in MS8 */ +} + +static void +nvc0_blit_set_src(struct nvc0_context *nvc0, + struct pipe_resource *res, unsigned level, unsigned layer) +{ + struct pipe_context *pipe = &nvc0->base.pipe; + struct pipe_sampler_view templ; + int s; + + templ.format = res->format; + templ.u.tex.first_layer = templ.u.tex.last_layer = layer; + templ.u.tex.first_level = templ.u.tex.last_level = level; + templ.swizzle_r = PIPE_SWIZZLE_RED; + templ.swizzle_g = PIPE_SWIZZLE_GREEN; + templ.swizzle_b = PIPE_SWIZZLE_BLUE; + templ.swizzle_a = PIPE_SWIZZLE_ALPHA; + + nvc0->textures[4][0] = nvc0_create_sampler_view(pipe, res, &templ); + + nvc0_blit_fixup_tic_entry(nvc0->textures[4][0]); + + for (s = 0; s <= 3; ++s) + nvc0->num_textures[s] = 0; + nvc0->num_textures[4] = 1; +} + +static void +nvc0_blitctx_prepare_state(struct nvc0_blitctx *blit) +{ + struct nouveau_channel *chan = blit->screen->base.channel; + + /* TODO: maybe make this a MACRO (if we need more logic) ? */ + + /* blend state */ + BEGIN_RING(chan, RING_3D(COLOR_MASK(0)), 1); + OUT_RING (chan, blit->color_mask); + BEGIN_RING(chan, RING_3D(BLEND_ENABLE(0)), 1); + OUT_RING (chan, 0); + IMMED_RING(chan, RING_3D(LOGIC_OP_ENABLE), 0); + + /* rasterizer state */ + BEGIN_RING(chan, RING_3D(FRAG_COLOR_CLAMP_EN), 1); + OUT_RING (chan, 0); + IMMED_RING(chan, RING_3D(MULTISAMPLE_ENABLE), 0); + BEGIN_RING(chan, RING_3D(MSAA_MASK(0)), 4); + OUT_RING (chan, 0xffff); + OUT_RING (chan, 0xffff); + OUT_RING (chan, 0xffff); + OUT_RING (chan, 0xffff); + BEGIN_RING(chan, RING_3D(POLYGON_MODE_FRONT), 1); + OUT_RING (chan, NVC0_3D_POLYGON_MODE_FRONT_FILL); + BEGIN_RING(chan, RING_3D(POLYGON_MODE_BACK), 1); + OUT_RING (chan, NVC0_3D_POLYGON_MODE_BACK_FILL); + IMMED_RING(chan, RING_3D(POLYGON_SMOOTH_ENABLE), 0); + IMMED_RING(chan, RING_3D(POLYGON_OFFSET_FILL_ENABLE), 0); + IMMED_RING(chan, RING_3D(POLYGON_STIPPLE_ENABLE), 0); + IMMED_RING(chan, RING_3D(CULL_FACE_ENABLE), 0); + + /* zsa state */ + IMMED_RING(chan, RING_3D(DEPTH_TEST_ENABLE), 0); + IMMED_RING(chan, RING_3D(STENCIL_ENABLE), 0); + IMMED_RING(chan, RING_3D(ALPHA_TEST_ENABLE), 0); + + /* transform feedback ? */ +} + +static void +nvc0_blitctx_pre_blit(struct nvc0_blitctx *blit, struct nvc0_context *nvc0) +{ + int s; + + blit->saved.fb.width = nvc0->framebuffer.width; + blit->saved.fb.height = nvc0->framebuffer.height; + blit->saved.fb.nr_cbufs = nvc0->framebuffer.nr_cbufs; + blit->saved.fb.cbufs[0] = nvc0->framebuffer.cbufs[0]; + blit->saved.fb.zsbuf = nvc0->framebuffer.zsbuf; + + blit->saved.vp = nvc0->vertprog; + blit->saved.tcp = nvc0->tctlprog; + blit->saved.tep = nvc0->tevlprog; + blit->saved.gp = nvc0->gmtyprog; + blit->saved.fp = nvc0->fragprog; + + nvc0->vertprog = &blit->vp; + nvc0->fragprog = &blit->fp; + nvc0->tctlprog = NULL; + nvc0->tevlprog = NULL; + nvc0->gmtyprog = NULL; + + blit->saved.clip_nr = nvc0->clip.nr; + + nvc0->clip.nr = 0; + + for (s = 0; s <= 4; ++s) { + blit->saved.num_textures[s] = nvc0->num_textures[s]; + blit->saved.num_samplers[s] = nvc0->num_samplers[s]; + } + blit->saved.texture = nvc0->textures[4][0]; + blit->saved.sampler = nvc0->samplers[4][0]; + + nvc0->samplers[4][0] = &blit->sampler[blit->filter]; + + for (s = 0; s <= 3; ++s) + nvc0->num_samplers[s] = 0; + nvc0->num_samplers[4] = 1; + + blit->saved.dirty = nvc0->dirty; + + nvc0->dirty = NVC0_NEW_FRAMEBUFFER | + NVC0_NEW_VERTPROG | NVC0_NEW_FRAGPROG | + NVC0_NEW_TCTLPROG | NVC0_NEW_TEVLPROG | NVC0_NEW_GMTYPROG | + NVC0_NEW_TEXTURES | NVC0_NEW_SAMPLERS; +} + +static void +nvc0_blitctx_post_blit(struct nvc0_context *nvc0, struct nvc0_blitctx *blit) +{ + int s; + + pipe_surface_reference(&nvc0->framebuffer.cbufs[0], NULL); + + nvc0->framebuffer.width = blit->saved.fb.width; + nvc0->framebuffer.height = blit->saved.fb.height; + nvc0->framebuffer.nr_cbufs = blit->saved.fb.nr_cbufs; + nvc0->framebuffer.cbufs[0] = blit->saved.fb.cbufs[0]; + nvc0->framebuffer.zsbuf = blit->saved.fb.zsbuf; + + nvc0->vertprog = blit->saved.vp; + nvc0->tctlprog = blit->saved.tcp; + nvc0->tevlprog = blit->saved.tep; + nvc0->gmtyprog = blit->saved.gp; + nvc0->fragprog = blit->saved.fp; + + nvc0->clip.nr = blit->saved.clip_nr; + + pipe_sampler_view_reference(&nvc0->textures[4][0], NULL); + + for (s = 0; s <= 4; ++s) { + nvc0->num_textures[s] = blit->saved.num_textures[s]; + nvc0->num_samplers[s] = blit->saved.num_samplers[s]; + } + nvc0->textures[4][0] = blit->saved.texture; + nvc0->samplers[4][0] = blit->saved.sampler; + + nvc0->dirty = blit->saved.dirty | + (NVC0_NEW_FRAMEBUFFER | NVC0_NEW_SCISSOR | NVC0_NEW_SAMPLE_MASK | + NVC0_NEW_RASTERIZER | NVC0_NEW_ZSA | NVC0_NEW_BLEND | + NVC0_NEW_TEXTURES | NVC0_NEW_SAMPLERS | + NVC0_NEW_VERTPROG | NVC0_NEW_FRAGPROG | + NVC0_NEW_TCTLPROG | NVC0_NEW_TEVLPROG | NVC0_NEW_GMTYPROG); +} + +static void +nvc0_resource_resolve(struct pipe_context *pipe, + const struct pipe_resolve_info *info) +{ + struct nvc0_context *nvc0 = nvc0_context(pipe); + struct nvc0_screen *screen = nvc0->screen; + struct nvc0_blitctx *blit = screen->blitctx; + struct nouveau_channel *chan = screen->base.channel; + struct pipe_resource *src = info->src.res; + struct pipe_resource *dst = info->dst.res; + float x0, x1, y0, y1; + float x_range, y_range; + + /* Would need more shader variants or, better, just change the TIC target. + * But no API creates 3D MS textures ... + */ + if (src->target == PIPE_TEXTURE_3D) + return; + + nvc0_blitctx_get_color_mask_and_fp(blit, dst->format, info->mask); + + blit->filter = util_format_is_depth_or_stencil(dst->format) ? 0 : 1; + + nvc0_blitctx_pre_blit(blit, nvc0); + + nvc0_blit_set_dst(nvc0, dst, info->dst.level, info->dst.layer); + nvc0_blit_set_src(nvc0, src, 0, info->src.layer); + + nvc0_blitctx_prepare_state(blit); + + nvc0_state_validate(nvc0, ~0, 36); + + x_range = + (float)(info->src.x1 - info->src.x0) / + (float)(info->dst.x1 - info->dst.x0); + y_range = + (float)(info->src.y1 - info->src.y0) / + (float)(info->dst.y1 - info->dst.y0); + + x0 = (float)info->src.x0 - x_range * (float)info->dst.x0; + y0 = (float)info->src.y0 - y_range * (float)info->dst.y0; + + x1 = x0 + 16384.0f * x_range; + y1 = y0 + 16384.0f * y_range; + + x0 *= (float)(1 << nv50_miptree(src)->ms_x); + x1 *= (float)(1 << nv50_miptree(src)->ms_x); + y0 *= (float)(1 << nv50_miptree(src)->ms_y); + y1 *= (float)(1 << nv50_miptree(src)->ms_y); + + BEGIN_RING(chan, RING_3D(SP_START_ID(5)), 1); + OUT_RING (chan, + blit->fp.code_base + blit->fp_offset); + + IMMED_RING(chan, RING_3D(VIEWPORT_TRANSFORM_EN), 0); + + /* Draw a large triangle in screen coordinates covering the whole + * render target, with scissors defining the destination region. + * The vertex is supplied with non-normalized texture coordinates + * arranged in a way to yield the desired offset and scale. + */ + + BEGIN_RING(chan, RING_3D(SCISSOR_HORIZ(0)), 2); + OUT_RING (chan, (info->dst.x1 << 16) | info->dst.x0); + OUT_RING (chan, (info->dst.y1 << 16) | info->dst.y0); + + IMMED_RING(chan, RING_3D(VERTEX_BEGIN_GL), + NVC0_3D_VERTEX_BEGIN_GL_PRIMITIVE_TRIANGLES); + + BEGIN_RING(chan, RING_3D(VTX_ATTR_DEFINE), 3); + OUT_RING (chan, 0x74201); + OUT_RINGf (chan, x0); + OUT_RINGf (chan, y0); + BEGIN_RING(chan, RING_3D(VTX_ATTR_DEFINE), 3); + OUT_RING (chan, 0x74200); + OUT_RINGf (chan, 0.0f); + OUT_RINGf (chan, 0.0f); + BEGIN_RING(chan, RING_3D(VTX_ATTR_DEFINE), 3); + OUT_RING (chan, 0x74201); + OUT_RINGf (chan, x1); + OUT_RINGf (chan, y0); + BEGIN_RING(chan, RING_3D(VTX_ATTR_DEFINE), 3); + OUT_RING (chan, 0x74200); + OUT_RINGf (chan, 16384 << nv50_miptree(dst)->ms_x); + OUT_RINGf (chan, 0.0f); + BEGIN_RING(chan, RING_3D(VTX_ATTR_DEFINE), 3); + OUT_RING (chan, 0x74201); + OUT_RINGf (chan, x0); + OUT_RINGf (chan, y1); + BEGIN_RING(chan, RING_3D(VTX_ATTR_DEFINE), 3); + OUT_RING (chan, 0x74200); + OUT_RINGf (chan, 0.0f); + OUT_RINGf (chan, 16384 << nv50_miptree(dst)->ms_y); + + IMMED_RING(chan, RING_3D(VERTEX_END_GL), 0); + + /* re-enable normally constant state */ + + IMMED_RING(chan, RING_3D(VIEWPORT_TRANSFORM_EN), 1); + + nvc0_blitctx_post_blit(nvc0, blit); +} + +boolean +nvc0_blitctx_create(struct nvc0_screen *screen) +{ + screen->blitctx = CALLOC_STRUCT(nvc0_blitctx); + if (!screen->blitctx) { + NOUVEAU_ERR("failed to allocate blit context\n"); + return FALSE; + } + + screen->blitctx->screen = screen; + + nvc0_blitctx_make_vp(screen->blitctx); + nvc0_blitctx_make_fp(screen->blitctx); + + nvc0_blitctx_make_sampler(screen->blitctx); + + screen->blitctx->color_mask = 0x1111; + + return TRUE; +} + + void nvc0_init_surface_functions(struct nvc0_context *nvc0) { struct pipe_context *pipe = &nvc0->base.pipe; pipe->resource_copy_region = nvc0_resource_copy_region; + pipe->resource_resolve = nvc0_resource_resolve; pipe->clear_render_target = nvc0_clear_render_target; pipe->clear_depth_stencil = nvc0_clear_depth_stencil; } - |