1af69d88dSmrg/*
2af69d88dSmrg * Copyright (C) 2014 Rob Clark <robclark@freedesktop.org>
3af69d88dSmrg *
4af69d88dSmrg * Permission is hereby granted, free of charge, to any person obtaining a
5af69d88dSmrg * copy of this software and associated documentation files (the "Software"),
6af69d88dSmrg * to deal in the Software without restriction, including without limitation
7af69d88dSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8af69d88dSmrg * and/or sell copies of the Software, and to permit persons to whom the
9af69d88dSmrg * Software is furnished to do so, subject to the following conditions:
10af69d88dSmrg *
11af69d88dSmrg * The above copyright notice and this permission notice (including the next
12af69d88dSmrg * paragraph) shall be included in all copies or substantial portions of the
13af69d88dSmrg * Software.
14af69d88dSmrg *
15af69d88dSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16af69d88dSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17af69d88dSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18af69d88dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19af69d88dSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20af69d88dSmrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21af69d88dSmrg * SOFTWARE.
22af69d88dSmrg *
23af69d88dSmrg * Authors:
24af69d88dSmrg *    Rob Clark <robclark@freedesktop.org>
25af69d88dSmrg */
26af69d88dSmrg
27af69d88dSmrg#include "tgsi/tgsi_text.h"
2801e04c3fSmrg#include "tgsi/tgsi_ureg.h"
29af69d88dSmrg
307ec681f3Smrg#include "util/u_simple_shaders.h"
317ec681f3Smrg
32af69d88dSmrg#include "freedreno_context.h"
337ec681f3Smrg#include "freedreno_program.h"
347ec681f3Smrg
357ec681f3Smrgstatic void
367ec681f3Smrgupdate_bound_stage(struct fd_context *ctx, enum pipe_shader_type shader,
377ec681f3Smrg                   bool bound) assert_dt
387ec681f3Smrg{
397ec681f3Smrg   if (bound) {
407ec681f3Smrg      ctx->bound_shader_stages |= BIT(shader);
417ec681f3Smrg   } else {
427ec681f3Smrg      ctx->bound_shader_stages &= ~BIT(shader);
437ec681f3Smrg   }
447ec681f3Smrg}
457ec681f3Smrg
467ec681f3Smrgstatic void
477ec681f3Smrgfd_set_patch_vertices(struct pipe_context *pctx, uint8_t patch_vertices) in_dt
487ec681f3Smrg{
497ec681f3Smrg   struct fd_context *ctx = fd_context(pctx);
507ec681f3Smrg
517ec681f3Smrg   ctx->patch_vertices = patch_vertices;
527ec681f3Smrg}
537ec681f3Smrg
547ec681f3Smrgstatic void
557ec681f3Smrgfd_vs_state_bind(struct pipe_context *pctx, void *hwcso) in_dt
567ec681f3Smrg{
577ec681f3Smrg   struct fd_context *ctx = fd_context(pctx);
587ec681f3Smrg   ctx->prog.vs = hwcso;
597ec681f3Smrg   fd_context_dirty_shader(ctx, PIPE_SHADER_VERTEX, FD_DIRTY_SHADER_PROG);
607ec681f3Smrg   update_bound_stage(ctx, PIPE_SHADER_VERTEX, !!hwcso);
617ec681f3Smrg}
627ec681f3Smrg
637ec681f3Smrgstatic void
647ec681f3Smrgfd_tcs_state_bind(struct pipe_context *pctx, void *hwcso) in_dt
657ec681f3Smrg{
667ec681f3Smrg   struct fd_context *ctx = fd_context(pctx);
677ec681f3Smrg   ctx->prog.hs = hwcso;
687ec681f3Smrg   fd_context_dirty_shader(ctx, PIPE_SHADER_TESS_CTRL, FD_DIRTY_SHADER_PROG);
697ec681f3Smrg   update_bound_stage(ctx, PIPE_SHADER_TESS_CTRL, !!hwcso);
707ec681f3Smrg}
717ec681f3Smrg
727ec681f3Smrgstatic void
737ec681f3Smrgfd_tes_state_bind(struct pipe_context *pctx, void *hwcso) in_dt
747ec681f3Smrg{
757ec681f3Smrg   struct fd_context *ctx = fd_context(pctx);
767ec681f3Smrg   ctx->prog.ds = hwcso;
777ec681f3Smrg   fd_context_dirty_shader(ctx, PIPE_SHADER_TESS_EVAL, FD_DIRTY_SHADER_PROG);
787ec681f3Smrg   update_bound_stage(ctx, PIPE_SHADER_TESS_EVAL, !!hwcso);
797ec681f3Smrg}
80af69d88dSmrg
81af69d88dSmrgstatic void
827ec681f3Smrgfd_gs_state_bind(struct pipe_context *pctx, void *hwcso) in_dt
83af69d88dSmrg{
847ec681f3Smrg   struct fd_context *ctx = fd_context(pctx);
857ec681f3Smrg   ctx->prog.gs = hwcso;
867ec681f3Smrg   fd_context_dirty_shader(ctx, PIPE_SHADER_GEOMETRY, FD_DIRTY_SHADER_PROG);
877ec681f3Smrg   update_bound_stage(ctx, PIPE_SHADER_GEOMETRY, !!hwcso);
88af69d88dSmrg}
89af69d88dSmrg
90af69d88dSmrgstatic void
917ec681f3Smrgfd_fs_state_bind(struct pipe_context *pctx, void *hwcso) in_dt
927ec681f3Smrg{
937ec681f3Smrg   struct fd_context *ctx = fd_context(pctx);
947ec681f3Smrg   ctx->prog.fs = hwcso;
957ec681f3Smrg   fd_context_dirty_shader(ctx, PIPE_SHADER_FRAGMENT, FD_DIRTY_SHADER_PROG);
967ec681f3Smrg   update_bound_stage(ctx, PIPE_SHADER_FRAGMENT, !!hwcso);
977ec681f3Smrg}
987ec681f3Smrg
997ec681f3Smrgstatic const char *solid_fs = "FRAG                                        \n"
1007ec681f3Smrg                              "PROPERTY FS_COLOR0_WRITES_ALL_CBUFS 1       \n"
1017ec681f3Smrg                              "DCL CONST[0]                                \n"
1027ec681f3Smrg                              "DCL OUT[0], COLOR                           \n"
1037ec681f3Smrg                              "  0: MOV OUT[0], CONST[0]                   \n"
1047ec681f3Smrg                              "  1: END                                    \n";
1057ec681f3Smrg
1067ec681f3Smrgstatic const char *solid_vs = "VERT                                        \n"
1077ec681f3Smrg                              "DCL IN[0]                                   \n"
1087ec681f3Smrg                              "DCL OUT[0], POSITION                        \n"
1097ec681f3Smrg                              "  0: MOV OUT[0], IN[0]                      \n"
1107ec681f3Smrg                              "  1: END                                    \n";
1117ec681f3Smrg
1127ec681f3Smrgstatic void *
1137ec681f3Smrgassemble_tgsi(struct pipe_context *pctx, const char *src, bool frag)
114af69d88dSmrg{
1157ec681f3Smrg   struct tgsi_token toks[32];
1167ec681f3Smrg   struct pipe_shader_state cso = {
1177ec681f3Smrg      .tokens = toks,
1187ec681f3Smrg   };
1197ec681f3Smrg
1207ec681f3Smrg   bool ret = tgsi_text_translate(src, toks, ARRAY_SIZE(toks));
1217ec681f3Smrg   assume(ret);
1227ec681f3Smrg
1237ec681f3Smrg   if (frag)
1247ec681f3Smrg      return pctx->create_fs_state(pctx, &cso);
1257ec681f3Smrg   else
1267ec681f3Smrg      return pctx->create_vs_state(pctx, &cso);
127af69d88dSmrg}
128af69d88dSmrg
1297ec681f3Smrg/* the correct semantic to use for the texcoord varying depends on pipe-cap: */
1307ec681f3Smrgstatic enum tgsi_semantic
1317ec681f3Smrgtexcoord_semantic(struct pipe_context *pctx)
132af69d88dSmrg{
1337ec681f3Smrg   struct pipe_screen *pscreen = pctx->screen;
1347ec681f3Smrg
1357ec681f3Smrg   if (pscreen->get_param(pscreen, PIPE_CAP_TGSI_TEXCOORD)) {
1367ec681f3Smrg      return TGSI_SEMANTIC_TEXCOORD;
1377ec681f3Smrg   } else {
1387ec681f3Smrg      return TGSI_SEMANTIC_GENERIC;
1397ec681f3Smrg   }
140af69d88dSmrg}
141af69d88dSmrg
14201e04c3fSmrgstatic void *
1437ec681f3Smrgfd_prog_blit_vs(struct pipe_context *pctx)
14401e04c3fSmrg{
1457ec681f3Smrg   struct ureg_program *ureg;
1467ec681f3Smrg
1477ec681f3Smrg   ureg = ureg_create(PIPE_SHADER_VERTEX);
1487ec681f3Smrg   if (!ureg)
1497ec681f3Smrg      return NULL;
1507ec681f3Smrg
1517ec681f3Smrg   struct ureg_src in0 = ureg_DECL_vs_input(ureg, 0);
1527ec681f3Smrg   struct ureg_src in1 = ureg_DECL_vs_input(ureg, 1);
1537ec681f3Smrg
1547ec681f3Smrg   struct ureg_dst out0 = ureg_DECL_output(ureg, texcoord_semantic(pctx), 0);
1557ec681f3Smrg   struct ureg_dst out1 = ureg_DECL_output(ureg, TGSI_SEMANTIC_POSITION, 1);
1567ec681f3Smrg
1577ec681f3Smrg   ureg_MOV(ureg, out0, in0);
1587ec681f3Smrg   ureg_MOV(ureg, out1, in1);
1597ec681f3Smrg
1607ec681f3Smrg   ureg_END(ureg);
1617ec681f3Smrg
1627ec681f3Smrg   return ureg_create_shader_and_destroy(ureg, pctx);
16301e04c3fSmrg}
16401e04c3fSmrg
1657ec681f3Smrgstatic void *
1667ec681f3Smrgfd_prog_blit_fs(struct pipe_context *pctx, int rts, bool depth)
1677ec681f3Smrg{
1687ec681f3Smrg   int i;
1697ec681f3Smrg   struct ureg_src tc;
1707ec681f3Smrg   struct ureg_program *ureg;
1717ec681f3Smrg
1727ec681f3Smrg   debug_assert(rts <= MAX_RENDER_TARGETS);
17301e04c3fSmrg
1747ec681f3Smrg   ureg = ureg_create(PIPE_SHADER_FRAGMENT);
1757ec681f3Smrg   if (!ureg)
1767ec681f3Smrg      return NULL;
1777ec681f3Smrg
1787ec681f3Smrg   tc = ureg_DECL_fs_input(ureg, texcoord_semantic(pctx), 0,
1797ec681f3Smrg                           TGSI_INTERPOLATE_PERSPECTIVE);
1807ec681f3Smrg   for (i = 0; i < rts; i++)
1817ec681f3Smrg      ureg_TEX(ureg, ureg_DECL_output(ureg, TGSI_SEMANTIC_COLOR, i),
1827ec681f3Smrg               TGSI_TEXTURE_2D, tc, ureg_DECL_sampler(ureg, i));
1837ec681f3Smrg   if (depth)
1847ec681f3Smrg      ureg_TEX(ureg,
1857ec681f3Smrg               ureg_writemask(ureg_DECL_output(ureg, TGSI_SEMANTIC_POSITION, 0),
1867ec681f3Smrg                              TGSI_WRITEMASK_Z),
1877ec681f3Smrg               TGSI_TEXTURE_2D, tc, ureg_DECL_sampler(ureg, rts));
1887ec681f3Smrg
1897ec681f3Smrg   ureg_END(ureg);
1907ec681f3Smrg
1917ec681f3Smrg   return ureg_create_shader_and_destroy(ureg, pctx);
1927ec681f3Smrg}
1937ec681f3Smrg
1947ec681f3Smrgvoid
1957ec681f3Smrgfd_prog_init(struct pipe_context *pctx)
196af69d88dSmrg{
1977ec681f3Smrg   struct fd_context *ctx = fd_context(pctx);
1987ec681f3Smrg   int i;
1997ec681f3Smrg
2007ec681f3Smrg   pctx->bind_vs_state = fd_vs_state_bind;
2017ec681f3Smrg   pctx->bind_tcs_state = fd_tcs_state_bind;
2027ec681f3Smrg   pctx->bind_tes_state = fd_tes_state_bind;
2037ec681f3Smrg   pctx->bind_gs_state = fd_gs_state_bind;
2047ec681f3Smrg   pctx->bind_fs_state = fd_fs_state_bind;
2057ec681f3Smrg   pctx->set_patch_vertices = fd_set_patch_vertices;
2067ec681f3Smrg
2077ec681f3Smrg   ctx->solid_prog.fs = assemble_tgsi(pctx, solid_fs, true);
2087ec681f3Smrg   ctx->solid_prog.vs = assemble_tgsi(pctx, solid_vs, false);
209af69d88dSmrg
2107ec681f3Smrg   if (ctx->screen->gen >= 6) {
2117ec681f3Smrg      ctx->solid_layered_prog.fs = assemble_tgsi(pctx, solid_fs, true);
2127ec681f3Smrg      ctx->solid_layered_prog.vs = util_make_layered_clear_vertex_shader(pctx);
2137ec681f3Smrg   }
214af69d88dSmrg
2157ec681f3Smrg   if (ctx->screen->gen >= 5)
2167ec681f3Smrg      return;
2179f464c52Smaya
2187ec681f3Smrg   ctx->blit_prog[0].vs = fd_prog_blit_vs(pctx);
2197ec681f3Smrg   ctx->blit_prog[0].fs = fd_prog_blit_fs(pctx, 1, false);
2209f464c52Smaya
2217ec681f3Smrg   if (ctx->screen->gen < 3)
2227ec681f3Smrg      return;
22301e04c3fSmrg
2247ec681f3Smrg   for (i = 1; i < ctx->screen->max_rts; i++) {
2257ec681f3Smrg      ctx->blit_prog[i].vs = ctx->blit_prog[0].vs;
2267ec681f3Smrg      ctx->blit_prog[i].fs = fd_prog_blit_fs(pctx, i + 1, false);
2277ec681f3Smrg   }
2287ec681f3Smrg
2297ec681f3Smrg   ctx->blit_z.vs = ctx->blit_prog[0].vs;
2307ec681f3Smrg   ctx->blit_z.fs = fd_prog_blit_fs(pctx, 0, true);
2317ec681f3Smrg   ctx->blit_zs.vs = ctx->blit_prog[0].vs;
2327ec681f3Smrg   ctx->blit_zs.fs = fd_prog_blit_fs(pctx, 1, true);
233af69d88dSmrg}
234af69d88dSmrg
2357ec681f3Smrgvoid
2367ec681f3Smrgfd_prog_fini(struct pipe_context *pctx)
237af69d88dSmrg{
2387ec681f3Smrg   struct fd_context *ctx = fd_context(pctx);
2397ec681f3Smrg   int i;
2407ec681f3Smrg
2417ec681f3Smrg   pctx->delete_vs_state(pctx, ctx->solid_prog.vs);
2427ec681f3Smrg   pctx->delete_fs_state(pctx, ctx->solid_prog.fs);
2437ec681f3Smrg
2447ec681f3Smrg   if (ctx->screen->gen >= 6) {
2457ec681f3Smrg      pctx->delete_vs_state(pctx, ctx->solid_layered_prog.vs);
2467ec681f3Smrg      pctx->delete_fs_state(pctx, ctx->solid_layered_prog.fs);
2477ec681f3Smrg   }
2487ec681f3Smrg
2497ec681f3Smrg   if (ctx->screen->gen >= 5)
2507ec681f3Smrg      return;
2517ec681f3Smrg
2527ec681f3Smrg   pctx->delete_vs_state(pctx, ctx->blit_prog[0].vs);
2537ec681f3Smrg   pctx->delete_fs_state(pctx, ctx->blit_prog[0].fs);
2547ec681f3Smrg
2557ec681f3Smrg   if (ctx->screen->gen < 3)
2567ec681f3Smrg      return;
2577ec681f3Smrg
2587ec681f3Smrg   for (i = 1; i < ctx->screen->max_rts; i++)
2597ec681f3Smrg      pctx->delete_fs_state(pctx, ctx->blit_prog[i].fs);
2607ec681f3Smrg   pctx->delete_fs_state(pctx, ctx->blit_z.fs);
2617ec681f3Smrg   pctx->delete_fs_state(pctx, ctx->blit_zs.fs);
262af69d88dSmrg}
263